Skip to main content

Card Deposits

Introduction

The Card Deposit Service offers a native card deposit flow for those who prefer not to build their own user interface or for applications that are not PCI DSS compliant. This service provides a secure, fully managed deposit experience, allowing users to add funds to their accounts using either a new or existing card. By leveraging Paysafe's PCI DSS-compliant infrastructure, sensitive card information is handled securely, enabling you to focus on your core application functionality.

Key Features:

  • Offers a native, customizable UI flow that you can adapt to match your app's design, minimizing the need to build one from scratch.
  • Supports 3D Secure (3DS) authentication to ensure a secure card deposit process.
  • You can choose between a full native experience, covering the entire deposit flow, or a partial integration focused on collecting card details, making it adaptable to your specific needs.

Prerequisites

Before integrating the Deposit Service, ensure you have:

  • A valid Paysafe account with appropriate permissions.
  • Set up instructions for Paysafe SDK Android or iOS.
  • Ensure that the user has the necessary permissions to make card deposits by accessing the DepositService and calling the getOptions method and verifying that the CARD option is included in the list of available deposit methods.

To get started, initialize the CardDepositService instance in your app as shown below:

import com.paysafe.wallet.android.core.wallet.Wallet

val cardDeposits = Wallet.getInstance().getCardDepositService()
warning

In order to integrate the card deposit native flow a parameter scope pci-dss-1 is required when issuing SDK JWT token. More information about PCI DSS can be found here.

Card Deposit User Experience Overview

In the card deposit native flow, users can choose to deposit funds using either a new card or an existing saved card. The type of flow Еmbedded or Outsourced, is determined when the preview method is called. Based on the card type and flow chosen, the following steps outline the user experience:

Native Card Deposit Flow OverviewNative Card Deposit Flow Overview

1. Input Card Information:

  • When depositing with a new card, users are shown a screen to input their card details. This includes entering the card number, expiry date, and CVV. Additionally, they have the option to save the card for future use and to assign a personalized nickname to the card.
  • For existing cards, users only need to enter the CVV, as the card number and other details are already stored and pre-filled in the form.

2. Embedded Flow:

  • After users enter the required details for a new or existing card, they are shown a screen to review the deposit details, including the deposit amount and any associated fees.
  • After confirming, if required, the user is prompted to complete 3DS authentication for enhanced security.
  • Once all steps are completed, control is returned to the client application, indicating the result of the deposit.

3. Outsourced Flow:

  • Once users have entered the required details (for new or existing card), control is returned to the client application.
  • The client application has the flexibility to display its own confirmation screen before completing the deposit and should handle any required actions to finalize the process.

Card Deposit Workflow Overview

Card Deposit Workflow OverviewCard Deposit Workflow OverviewCard Deposit Workflow OverviewCard Deposit Workflow Overview

1. Get Payment Instrument (optional):

When initiating a card deposit with an existing card, you will need to pass paymentInstrumentReference containing the information of the saved card. Then, use the PaymentInstrumentService and call the getAll method and retrieve the user's saved cards. After selecting a card, save its details to be used when initiating the deposit. If the user is depositing with a new card, simply proceed.

2. Card Deposit Steps:

To create a deposit, you will follow a three-step process: preview, start and confirm. Each method plays a specific role in moving the deposit through its lifecycle. There are two types of the native card deposit flow: an Embedded flow, which handles both card information collection and deposit processing, and an Outsourced flow, which only covers the card information collection. By default, the system uses the Embedded flow.

1. Preview Deposit

The preview method is the first step in the card deposit process. It allows you to validate the card deposit parameters before actually creating the deposit. This step creates a deposit in PREVIEW state, which does not perform any transaction in the Paysafe Wallet system. Instead, it checks the deposit's configuration.

Purpose: To validate the deposit parameters (e.g., amount, instrument, etc.).

Output: A CustomerDeposit object is returned, which is needed for the next steps.

2. Start Deposit

Once the deposit has been previewed, the start method is called to initiate the native card deposit flow. This method launches the user interface, allowing users to enter their card details or confirm an existing card, while performing any necessary validations such as 3D Secure (3DS) authentication when using the Embedded flow. Once the deposit flow is completed, the control is returned to the client application.

Purpose: To guide the user through the card deposit process, performing necessary security and validation checks, and moving the deposit toward completion.

Output: After the native card deposit flow has been completed, the result is returned to the client application in the form of a CardDepositResult object. This result indicates the outcome of the card deposit process, which can be a successful completion, a failure, or a cancellation. Based on the returned result, appropriate actions must be taken to finalize the deposit process or handle any errors.

Result Types:

  • Completed: The card deposit flow has been completed, but this doesn't necessarily mean that the deposit is successful. You may need to check the status or perform additional actions.
  • Terminal Failure: The deposit process has failed and cannot be retried. Appropriate error handling must be implemented.
  • Non-Terminal Failure: The deposit process encountered an issue but can be retried. The user can call the start method with the same deposit ID.
  • Cancelled: The deposit flow was cancelled by the user.
3. Confirm Deposit (optional)

The confirm method should only be called when using the Outsourced flow. This method transitions the deposit into PROCESSING state, indicating that the payment is being processed by the payment provider and is actively moving through the system.

Purpose: To confirm the deposit and initiate the actual processing of the payment.

Outcome: The deposit is moved to PROCESSING state, and you may need to handle redirection.

warning

To initiate the Outsourced flow, include the returnUrl when creating the CardDepositRequest. If the returnUrl is not provided, the Embedded card deposit flow will be triggered by default.

In the Outsourced flow, after the card details are collected and the user completes the initial steps, the client application must call the confirm method to move the deposit to PROCESSING state. At this stage, the client application is responsible for handling any required actions to finalize the deposit, such as completing 3D Secure (3DS) authentication.

Card Deposit Types

The Paysafe Wallet SDK supports two primary methods for card deposits: using an existing card or a new card. These methods cater to different user scenarios, allowing seamless integration of card deposits into your application. Below are the key steps and differences for each type of card deposit:

Deposit With New Card

When a user opts to deposit with a new card, the card details will need to be entered and validated during the deposit process. This method is ideal for first-time users or when the user wants to add a new card to their account.

Embedded Deposit With New Card

Steps for creating an Embedded deposit with a new card:

Step 1: Begin by calling the preview method and passing null/nil for the paymentInstrumentReference, as no stored card will be used. This step generates a depositId that will be required for the next steps. For the Embedded flow you should not pass returnUrl and method.

Step 2: Call the start method with the saved depositId from the CustomerDeposit object to initiate the native card deposit flow. During this step, the user will be prompted to enter their new card details, which may include completing a 3D Secure (3DS) authentication challenge.

Details about the CustomerDeposit object are available here.

// Step 1 - Preview
val cardDepositRequest = CardDepositRequest(
amount = 100,
currencyCode = "USD",
paymentInstrumentReference = null,
merchantRefNum = "2b01127a-4929-4d0e-b9cb-a29a8d1c499c"
)
val depositId: String

try {
val cardDepositPreview = cardDeposits.preview(cardDepositRequest)
depositId = cardDepositPreview.depositId
} catch (exception: Exception) {
// handle exception
return
}

// Step 2 - Start card deposit screen for result with launcher
val launcher = registerForActivityResult(OpenStartCardDeposit()) { result ->
when (result) {
CardDepositResult.Cancelled -> handleCancelled()
is CardDepositResult.TerminalFailure -> handleTerminalFailure()
is CardDepositResult.NonTerminalFailure -> handleNonTerminalFailure()
CardDepositResult.Completed -> handleCompleted()
else -> handleOtherResult()
}
}
launcher.launch(depositId)

Alternatively for Step 2 you can use startActivityForResult method:

 // Step 2 - Start card deposit screen for result
cardDepositService.start(this@MainActivity , EXTRA_CARD_DEPOSIT_RESULT, depositId)

// Then, obtain the card deposit result in onActivityResult
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == 100 && data != null) {
val result = IntentCompat.getParcelableExtra(
data,
EXTRA_CARD_DEPOSIT_RESULT,
CardDepositResult::class.java
)
when (result) {
CardDepositResult.Cancelled -> handleCancelled()
is CardDepositResult.TerminalFailure -> handleTerminalFailure()
is CardDepositResult.NonTerminalFailure -> handleNonTerminalFailure()
CardDepositResult.Completed -> handleCompleted()
else -> handleOtherResult()
}
}
}
Outsourced Deposit With New Card

Steps for creating an Outsourced deposit with a new card:

Step 1: Begin by calling the preview method and passing null/nil for the paymentInstrumentReference, as no stored card will be used. This step generates a depositId that will be required for the next steps. For the Outsourced flow, you should provide a returnUrl and can optionally specify the method, which defaults to GET.

Step 2: Call the start method with the saved depositId from the CustomerDeposit object to initiate the native card deposit flow. During this step, the user will be prompted to enter their new card details.

Step 3: Call the confirm method with the depositId. After confirming the deposit, the response may include a redirect action to complete a 3DS challenge. To finalize the deposit, use the redirectUrl to direct the user to the appropriate 3DS page.

Details about the CustomerDeposit object are available here.

// Step 1 - Preview
val cardDepositRequest = CardDepositRequest(
amount = 100,
currencyCode = "USD",
paymentInstrumentReference = null,
merchantRefNum = "2b01127a-4929-4d0e-b9cb-a29a8d1c499c",
returnUrl = "https://www.example.com",
method = HttpRequestMethod.GET
)
val depositId: String

try {
val cardDepositPreview = cardDeposits.preview(cardDepositRequest)
depositId = cardDepositPreview.depositId
} catch (exception: Exception) {
// handle exception
return
}

// Step 2 - Start card deposit screen for result with launcher
val launcher = registerForActivityResult(OpenStartCardDeposit()) { result ->
when (result) {
CardDepositResult.Cancelled -> handleCancelled()
is CardDepositResult.TerminalFailure -> handleTerminalFailure()
is CardDepositResult.NonTerminalFailure -> handleNonTerminalFailure()
CardDepositResult.Completed -> handleCompleted()
else -> handleOtherResult()
}
}
launcher.launch(depositId)

// Step 3 - Confirm
val cardDepositConfirm = CardDepositConfirm(depositId = depositId)
try {
val customerDeposit = cardDeposits.confirm(cardDepositConfirm)
// Handle successful deposit confirmation
} catch (exception: WalletException) {
// handle exception
return
}

Alternatively for Step 2 you can use startActivityForResult method:

 // Step 2 - Start card deposit screen for result
cardDepositService.start(this@MainActivity , EXTRA_CARD_DEPOSIT_RESULT, depositId)

// Then, obtain the card deposit result in onActivityResult
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == 100 && data != null) {
val result = IntentCompat.getParcelableExtra(
data,
EXTRA_CARD_DEPOSIT_RESULT,
CardDepositResult::class.java
)
when (result) {
CardDepositResult.Cancelled -> handleCancelled()
is CardDepositResult.TerminalFailure -> handleTerminalFailure()
is CardDepositResult.NonTerminalFailure -> handleNonTerminalFailure()
CardDepositResult.Completed -> handleCompleted()
else -> handleOtherResult()
}
}
}

Deposit With Existing Card

When a user opts to deposit with an existing card, the saved card details are used to streamline the process without requiring the user to re-enter their information. This method is ideal for returning users who have previously stored their card on the system, providing a faster and more convenient deposit experience. Additionally, it reduces friction in the deposit flow, making it a preferred option for users who frequently make deposits using the same card.

Embedded Deposit With Existing Card

Steps for creating a Embedded deposit with an existing card:

Step 1: Begin by calling the preview method and passing the paymentInstrumentReference with the data of the chosen card. This step generates a depositId that will be required for the next steps. For the Embedded flow you should not pass returnUrl and method.

Step 2: Call the start method with the saved depositId from the CustomerDeposit object to initiate the native card deposit flow. During this step, the user will be prompted to enter their cvv details, which may include completing a 3D Secure (3DS) authentication challenge.

Details about the CustomerDeposit object are available here.


val existingCardId = "11123"

// Step 1 - Preview

val cardDepositRequest = CardDepositRequest(
amount = 100,
currencyCode = "USD",
paymentInstrumentReference = PaymentInstrumentReference(
id = existingCardId,
instrumentType = InstrumentType.CARD
),
merchantRefNum = "2b01127a-4929-4d0e-b9cb-a29a8d1c499c"
)

try {
val cardDepositPreview = cardDeposits.preview(cardDepositRequest)
} catch (exception: Exception) {
// handle exception
}

// Step 2 - Start card deposit screen for result with launcher
val launcher = registerForActivityResult(OpenStartCardDeposit()) { result ->
when (result) {
CardDepositResult.Cancelled -> handleCancelled()
is CardDepositResult.TerminalFailure -> handleTerminalFailure()
is CardDepositResult.NonTerminalFailure -> handleNonTerminalFailure()
CardDepositResult.Completed -> handleCompleted()
else -> handleOtherResult()
}
}
launcher.launch(depositId)

Alternatively for Step 2 you can use startActivityForResult method:

 // Step 2 - Start card deposit screen for result
cardDepositService.start(this@MainActivity , EXTRA_CARD_DEPOSIT_RESULT, depositId)

// Then, obtain the card deposit result in onActivityResult
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == 100 && data != null) {
val result = IntentCompat.getParcelableExtra(
data,
EXTRA_CARD_DEPOSIT_RESULT,
CardDepositResult::class.java
)
when (result) {
CardDepositResult.Cancelled -> handleCancelled()
is CardDepositResult.TerminalFailure -> handleTerminalFailure()
is CardDepositResult.NonTerminalFailure -> handleNonTerminalFailure()
CardDepositResult.Completed -> handleCompleted()
else -> handleOtherResult()
}
}
}
Outsourced Deposit With Existing Card

Steps for creating an Outsourced deposit with a new card:

Step 1: Begin by calling the preview method and passing the paymentInstrumentReference with the data of the chosen card. This step generates a depositId that will be required for the next steps. For the Outsourced flow, you should provide a returnUrl and can optionally specify the method, which defaults to GET.

Step 2: Call the start method with the saved depositId from the CustomerDeposit object to initiate the native card deposit flow. During this step, the user will be prompted to enter their cvv details.

Step 3: Call the confirm method with the depositId. After confirming the deposit, the response may include a redirect action to complete a 3DS challenge. To finalize the deposit, use the redirectUrl to direct the user to the appropriate 3DS page.

Details about the CustomerDeposit object are available here.

// Step 1 - Preview

val existingCardId = "11123"

val cardDepositRequest = CardDepositRequest(
amount = 100,
currencyCode = "USD",
paymentInstrumentReference = PaymentInstrumentReference(
id = existingCardId,
instrumentType = InstrumentType.CARD
),
merchantRefNum = "2b01127a-4929-4d0e-b9cb-a29a8d1c499c",
returnUrl = "https://www.example.com",
method = HttpRequestMethod.GET
)

try {
val cardDepositPreview = cardDeposits.preview(cardDepositRequest)
} catch (exception: Exception) {
// handle exception
}

// Step 2 - Start card deposit screen for result with launcher
val launcher = registerForActivityResult(OpenStartCardDeposit()) { result ->
when (result) {
CardDepositResult.Cancelled -> handleCancelled()
is CardDepositResult.TerminalFailure -> handleTerminalFailure()
is CardDepositResult.NonTerminalFailure -> handleNonTerminalFailure()
CardDepositResult.Completed -> handleCompleted()
else -> handleOtherResult()
}
}
launcher.launch(depositId)

// Step 3 - Confirm
val cardDepositConfirm = CardDepositConfirm(depositId = depositId)
try {
val customerDeposit = cardDeposits.confirm(cardDepositConfirm)
// Handle successful deposit confirmation
} catch (exception: WalletException) {
// handle exception
return
}

Alternatively for Step 2 you can use startActivityForResult method:

 // Step 2 - Start card deposit screen for result
cardDepositService.start(this@MainActivity , EXTRA_CARD_DEPOSIT_RESULT, depositId)

// Then, obtain the card deposit result in onActivityResult
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == 100 && data != null) {
val result = IntentCompat.getParcelableExtra(
data,
EXTRA_CARD_DEPOSIT_RESULT,
CardDepositResult::class.java
)
when (result) {
CardDepositResult.Cancelled -> handleCancelled()
is CardDepositResult.TerminalFailure -> handleTerminalFailure()
is CardDepositResult.NonTerminalFailure -> handleNonTerminalFailure()
CardDepositResult.Completed -> handleCompleted()
else -> handleOtherResult()
}
}
}