Transfers
Introduction
The Transfer service offers a solution for moving funds between different wallet customers. Facilitates Strong Customer Authentication (SCA) when required and allows you to review applicable fees.
Key Features:
- Simulate a transfer to check fees and validate transfer details without creating an actual transaction.
- Perform necessary validations and initiate a transfer process.
- Confirm the transfer and move it to the processing stage, finalizing the payment flow.
- Retrieve a list of outbound or inbound transfers, view details of a specific transfer.
Prerequisites
Before integrating the Transfer service, ensure you have:
- A valid Paysafe account with appropriate permissions.
- Set up instructions for Paysafe SDK Android or iOS.
To get started, initialize the TransferService instance in your app as shown below:
- Kotlin
- Swift
import com.paysafe.wallet.android.core.wallet.Wallet
val transferService = Wallet.getInstance().getTransferService()
import PaysafeWallet
let transferService = Wallet.instance.transferService
Transfer Workflow Overview
- Sender Workflow
- Recipient Workflow
1. Preview transfer
The transfer process starts with the preview method, which serves as the first step in validating the transfer details before proceeding further. This step creates a transfer in PREVIEW state, which does not perform any transaction in the Paysafe Wallet system. Instead, it checks the transfer's configuration, such as recipient, fees and FX (currency exchange) amount (if applicable).
You could transfer money via email, mobile number or customerID.
The customer must have enough balance in the requested currency to complete the transfer.
- Kotlin
- Swift
The preview method is called with a CustomerTransferRequest object, which contains all the necessary information for the transfer.
val transferRequest = CustomerTransferRequest(
amount = 200,
currencyCode = "USD",
recipient = CustomerTransferRecipient(
customerId = null,
email = "user@example.com"
),
merchantRefNum = "2b01127a-4929-4d0e-b9cb-a29a8d1c499c",
transferDetails = TransferDetails(
reason = TransferReason.PEER_TRANSFER,
description = "Transfer money"
)
)
val transferPreview = transferService.preview(transferRequest)
The preview method is called with a CustomerTransferRequest object, which contains all the necessary information for the transfer.
let transferRequest = Wallet.CustomerTransferRequest(amount: 100,
currencyCode: "USD",
recipient: .init(email: "user@example.com"),
merchantRefNum: "2b01127a-4929-4d0e-b9cb-a29a8d1c499c",
transferDetails: .init(reason: .peerTransfer,
description: "Transfer money"))
transferService.preview(transferRequest: transferRequest, completion: { result in
switch result {
case .success(let transferPreview):
// Handle transferPreview
case .failure(let error):
// Handle error
}
})
2. Complete transfer
To move forward and complete the transfer, different steps are required based on whether the nextStatus of the preview response is SCHEDULED or PENDING.
Handle PENDING status
Step 1: Once the transfer has been previewed, you need to use the create method to validate and move the transfer to the PENDING state. At this point, all necessary checks are performed, and the system prepares the transfer for processing.
Purpose: To perform the required validations and transition the transfer into a state where it is ready for processing.
Outcome: The transfer is now in PENDING state, meaning it is fully validated and ready to proceed to the next step, confirmation.
- Kotlin
- Swift
val transferCreate = TransferCreate(transferId = "urn:transfer:01HNDA4FJJTN4TK66WK4251SWH")
val transfer = transferService.create(transferCreate)
let transferCreate = Wallet.TransferCreate(id: "urn:transfer:01HNDA4FJJTN4TK66WK4251SWH")
transferService.create(transferCreate: transferCreate, completion: { result in
switch result {
case .success(let transfer):
// Handle transfer
case .failure(let error):
// Handle error
}
})
Step 2: After the transfer has been successfully created and validated, the second step is using the confirm method to transition the transfer into the PROCESSING state. This state indicates that the payment is being processed and the transfer is actively moving through the system.
Purpose: To confirm the transfer and initiate the actual processing of the payment.
Outcome: The transfer moves to PROCESSING state. However, if Strong Customer Authentication (SCA) is required, the transfer will remain in the PENDING state until the SCA challenge is completed.
This operation might require Strong Customer Authentication (SCA).
Please read Strong Customer Authentication for more information on the process.
If the Transfer object returned by confirm has action: PaymentCompletionAction.SCA,
the scaDetails will contain the SCA authentication properties needed to complete the process.
Follow the steps outlined in Submit the SCA Authentication
to confirm the event. After the SCA event is accepted, invoke confirm method again,
providing scaDetails in the TransferConfirm parameter.
- Kotlin
- Swift
val transferId = "urn:transfer:01HNDA4FJJTN4TK66WK4251SWH"
val transferConfirm = TransferConfirm(transferId)
runCatching {
transferService.confirm(transferConfirm)
}.onSuccess { transfer ->
transfer.scaDetails?.let { scaDetails ->
// solve SCA challenge with these details
// as described in https://docs.paysafe.com/docs/embedded-wallets/strong-customer-authentication
// repeat the confirm call once the SCA challenge is solved
val scaDetailsRequest = ScaAuthenticationEventRequest(
eventId = scaDetails.eventId,
walletOperationId = scaDetails.walletOperationId,
)
transferService.confirm(
TransferConfirm(
transferId = transferId,
paymentProperties = null,
scaDetails = scaDetailsRequest
)
)
} ?: // If the received transfer does not contain SCA details, the transfer is confirmed
}
let transferService = Wallet.instance.transferService
let transferConfirm = Wallet.TransferConfirm(id: "urn:transfer:01HNDA4FJJTN4TK66WK4251SWH")
transferService.confirm(transferConfirm: transferConfirm, completion: { result in
switch result {
case .success(let transfer):
if transfer.action == .sca, let scaDetails = transferConfirm.scaDetails {
// solve SCA challenge with these details
// as described in https://docs.paysafe.com/docs/embedded-wallets/strong-customer-authentication
// repeat the confirm call once the SCA challenge is solved
let scaDetailsRequest = Wallet.SCAAuthenticationEventRequest(
eventID: scaDetails.eventID,
walletOperationID: scaDetails.walletOperationID
)
transferService.confirm(transferConfirm: Wallet.TransferConfirm(id: transferConfirm.id,
scaDetails: scaDetailsRequest),
completion: { result in
// Handle result
})
} else {
// Handle transfer
}
case .failure(let error):
// Handle error
}
})
Handle SCHEDULED status
Step 1: Once the transfer has been previewed, use the schedule method to validate and move the transfer to the SCHEDULED state.
Purpose: To perform the required validations and transition the transfer into a state where it is ready for accepting.
Outcome: The transfer moves to SCHEDULED state.
This operation might require Strong Customer Authentication (SCA).
Please read Strong Customer Authentication for more information on the process.
If the Transfer object returned by schedule has action: PaymentCompletionAction.SCA,
the scaDetails will contain the SCA authentication properties needed to complete the process.
Follow the steps outlined in Submit the SCA Authentication
to confirm the event. After the SCA event is accepted, invoke schedule method again,
providing scaDetails in the TransferSchedule parameter.
- Kotlin
- Swift
val transferId = "urn:transfer:01HNDA4FJJTN4TK66WK4251SWH"
val transferSchedule = TransferSchedule(transferId)
runCatching {
transferService.schedule(transferSchedule)
}.onSuccess { transfer ->
transfer.scaDetails?.let { scaDetails ->
// solve SCA challenge with these details
// as described in https://docs.paysafe.com/docs/embedded-wallets/strong-customer-authentication
// repeat the schedule call once the SCA challenge is solved
val scaDetailsRequest = ScaAuthenticationEventRequest(
eventId = scaDetails.eventId,
walletOperationId = scaDetails.walletOperationId,
)
transferService.schedule(
TransferSchedule(
transferId = transferId,
paymentProperties = null,
scaDetails = scaDetailsRequest
)
)
} ?: // If the received transfer does not contain SCA details, the transfer is scheduled
}
let transferService = Wallet.instance.transferService
let transferSchedule = Wallet.TransferSchedule(id: "urn:transfer:01HNDA4FJJTN4TK66WK4251SWH")
transferService.schedule(transferSchedule: transferSchedule, completion: { result in
switch result {
case .success(let transfer):
if transfer.action == .sca, let scaDetails = transferSchedule.scaDetails {
// solve SCA challenge with these details
// as described in https://docs.paysafe.com/docs/embedded-wallets/strong-customer-authentication
// repeat the schedule call once the SCA challenge is solved
let scaDetailsRequest = Wallet.SCAAuthenticationEventRequest(
eventID: scaDetails.eventID,
walletOperationID: scaDetails.walletOperationID
)
transferService.schedule(transferSchedule: Wallet.TransferSchedule(id: transferSchedule.id,
scaDetails: scaDetailsRequest),
completion: { result in
// Handle result
})
} else {
// Handle transfer
}
case .failure(let error):
// Handle error
}
})
Step 2: For the recipient to successfully receive the transfer, they should accept it using the accept method. If necessary, both you and the recipient have the option to cancel the scheduled transfer using the cancel method.
Purpose: To allow the recipient to accept the transfer and complete the process, or to provide the option to cancel before acceptance.
Outcome: If accepted, the funds are transferred to the recipient’s account. If canceled, the transfer is voided, and the funds return to the sender’s account.
To get the scheduled transfers that the recipient can act on, first retrieve the inbound transfers using getAllInbound (see Get Inbound Transfers List). Then use the selected transfer id with accept or cancel.
Accepting transfer is a two-way operation and occurs only when money is being transferred between two accounts for the first time.
- Kotlin
- Swift
// Accepting a scheduled transfer
val transferAccept = TransferAccept(transferId = "urn:transfer:01HNDA4FJJTN4TK66WK4251SWH")
val transfer = transferService.accept(transferAccept)
// Canceling a scheduled transfer
val transferCancel = TransferCancel(transferId = "urn:transfer:01HNDA4FJJTN4TK66WK4251SWH")
val transfer = transferService.cancel(transferCancel)
// Accepting a scheduled transfer
let transferAccept = Wallet.TransferAccept(id: "urn:transfer:01HNDA4FJJTN4TK66WK4251SWH")
transferService.accept(transferAccept: transferAccept, completion: { result in
switch result {
case .success(let transfer):
// Handle transfer
case .failure(let error):
// Handle error
}
})
// Canceling a scheduled transfer
let transferCancel = Wallet.TransferCancel(id: "urn:transfer:01HNDA4FJJTN4TK66WK4251SWH")
transferService.cancel(transferCancel: transferCancel, completion: { result in
switch result {
case .success(let transfer):
// Handle transfer
case .failure(let error):
// Handle error
}
})
List transfers
In addition to the methods for initiating transfer, the Transfer Service provides methods to retrieve transfer information.
Get Outbound Transfers List:
- Kotlin
- Swift
Use getAllOutbound method to retrieve the outbound transfers for the current customer. If no parameters are passed, the last 10 transfers are returned by default.
To apply filters, pass GetTransferParameters. Details about the object can be found here.
val getTransferParameters = GetTransferParameters(
limit = 10,
merchantRefNum = "2b01127a-4929-4d0e-b9cb-a29a8d1c499c",
offset = 10,
slipId = "123"
)
val transfersList = transferService.getAllOutbound(getTransferParameters)
Use getAllOutbound method to retrieve the outbound transfers for the current customer. If no parameters are passed, the last 10 transfers are returned by default.
To apply filters, pass the GetTransferParameters.
let getTransferParameters = Wallet.GetTransferParameters(limit: 10,
merchantRefNum: "2b01127a-4929-4d0e-b9cb-a29a8d1c499c",
offset: 10,
slipID: "123")
transferService.getAllOutbound(getTransferParameters: getTransferParameters, completion: { result in
switch result {
case .success(let transfers):
// Handle transfers
case .failure(let error):
// Handle error
}
})
Get a Single Outbound Transfer:
To retrieve details of a specific outbound transfer use getOutbound method with its id. Ensure that the transfer id is valid to receive the correct data.
- Kotlin
- Swift
val transferId = "urn:transfer:01HNDA4FJJTN4TK66WK4251SWH"
val transfer = transferService.getOutbound(transferId)
let transferId = "urn:transfer:01HNDA4FJJTN4TK66WK4251SWH"
transferService.getOutbound(id: transferId, completion: { result in
switch result {
case .success(let transfer):
// Handle transfer
case .failure(let error):
// Handle error
}
})
Get Inbound Transfers List
Use getAllInbound to retrieve transfers where the current customer is the recipient. If no parameters are passed, the last 10 transfers are returned by default.
- Kotlin
- Swift
Use getAllInbound method to retrieve a list of inbound transfers by passing the GetInboundTransferParameters. Details about the object can be found here.
val getInboundTransferParameters = GetInboundTransferParameters(
limit = 10,
offset = 10
)
val inboundTransfersList = transferService.getAllInbound(getInboundTransferParameters)
Use getAllInbound method to retrieve a list of inbound transfers by passing the GetTransferParameters.
let getTransferParameters = Wallet.GetTransferParameters(limit: 10,
offset: 10)
transferService.getAllInbound(getTransferParameters: getTransferParameters, completion: { result in
switch result {
case .success(let inboundTransfers):
// Handle inbound transfers
case .failure(let error):
// Handle error
}
})
Get a Single Inbound Transfer
To retrieve details of a specific inbound transfer use getInbound method with its id.
- Kotlin
- Swift
val transferId = "urn:transfer:01HNDA4FJJTN4TK66WK4251SWH"
val inboundTransfer = transferService.getInbound(transferId)
let transferId = "urn:transfer:01HNDA4FJJTN4TK66WK4251SWH"
transferService.getInbound(id: transferId, completion: { result in
switch result {
case .success(let inboundTransfer):
// Handle inbound transfer
case .failure(let error):
// Handle error
}
})