Search…
Manage Transactions
Provides the ability for a user to monitor and track the transactions performed on their virtual cards.
Transaction records represent a transaction performed against a provisioned virtual card (for more information on virtual cards, see here). Transactions cannot be created or deleted by the consumer directly. Transactions are generated by using the virtual card to make purchases at merchants.
Each transaction record has a sequenceId property which can be used to cross reference related transactions. For example, a pending transaction may have already been partially transacted and have related debit transactions (for more information on transaction states, see here).
Transactions may also contain a detail property which includes some supplementary information. For more information, see here.

Transaction States

Transactions can exist in 4 different states:
  • pending
  • complete
  • refund
  • decline
When a transaction is pending, it has entered the first state of authorization and is currently awaiting to be debited, or further action. A transaction that is pending will typically be completely debited, thus deleting the existing pending transaction, and being replaced with a debit transaction. A transaction can be partially debited however, which means that a new debit transaction record will be created for each partial debit.
A pending transaction record will continue to persist until its value has been decreased to 0, either via debits or reversal charges. Reversals will not be recorded via the transaction records, except through the decreasing value of the pending transaction. This is not to be confused with a refund transaction, which will generate a new transaction record.
Note - Reversal transactions relate to a transaction that has had its value decreased before it has been fully transacted (completed). A refunded transaction occurs after a fully completed transaction.
When a transaction is represented as being complete, it has entered a state that represents a successful debit. A completed transaction can be associated with a previously pending transaction via the sequenceId if the completed transaction was a partial debit.
When a transaction is represented as a refund, it means that a previously transacted record (state is complete) has been refunded. This can be either for a partial amount or the full amount. If a transaction is refunded, it will not remove the complete transaction record.
When a transaction is represented as a decline, it means that an error has occurred while attempting to process a transaction. For more information on decline reasons, see here.

Transaction Details

Transactions can contain supplementary details in the form of the detail property. Pending, complete, and refund transactions will always contain at least 1 detail. The information contained in details is recorded below:
Detail
Summary
virtualCardAmount
Amount merchant charged virtual card
markup
Markup formula applied to billedAmount to calculate
markupAmount
Markup amount added to transaction's transactedAmount
fundingSourceAmount
Amount charged to the funding source
fundingSourceId
ID of the funding source that funded this item
description
Description that will show on the real funding source statement

Decline Reasons

A transaction can be declined for a number of reasons. The table below shows a list of reasons and what they mean:
Reason
Cause
INSUFFICIENT_FUNDS
Funding source related to card has insufficent funds to perform the transaction
FUNDING_ERROR
Funding source related to card declined to perform the transaction for a reason other than insufficient funds.
CARD_STOPPED
Card associated with the transaction is inactive. This will occur implicitly if the funding source is also inactive
CARD_EXPIRED
Card associated with the transaction has expired.
MERCHANT_BLOCKED
Merchant that has been attempted to transact with is restricted
MERCHANT_CODE_BLOCKED
The merchant category code (MCC) of the merchant that has been attempted to transact with is restricted
MERCHANT_COUNTRY_BLOCKED
The country of the merchant that has been attempted to transact with is restricted
AVS_CHECK_FAILED
Address verification has failed
CSC_CHECK_FAILED
CSC verification has failed - occurs when the CSC provided to the merchant does not match the CSC of the virtual card
EXPIRY_CHECK_FAILED
Expiry verification has failed - occurs when the expiry date provided to the merchant does not match the expiry date of the virtual card
PROCESSING_ERROR
An error has occurred while attempting to process the transaction. Please contact support
DECLINED
Transaction is declined
VELOCITY_EXCEEDED
The transaction has exceeded its velocity policies
CURRENCY_BLOCKED
The transaction that has been attempted is in an unsupported currency

Retrieving Transactions

Transactions can be accessed in two ways: via its identifier (Single Transaction by Id), or via a list method (Multiple Transactions).
A fetch of single or multiple transactions can be performed remotely or locally by specifying the appropriate CachePolicy as part of the input.

Single Transaction by Id

To retrieve a single virtual card given its unique id, use the getTransaction method. This method will return the record if it exists.
TypeScript
Swift
Kotlin
try {
const transaction = await virtualCardsClient.getTransaction({
id,
cachePolicy: CachePolicy.RemoteOnly
})
// `transaction` contains the transaction object, else `undefined` if not found.
} catch (error) {
// Handle/notify error
}
do {
let transaction = try await self.virtualCardsClient.getTransaction(
withId: id,
cachePolicy: .remoteOnly
)
// If the id matches a transaction, `transaction` will be returned, else nil.
} catch {
// Handle/notify user of error
}
launch {
try {
val transaction = withContext(Dispatchers.IO) {
virtualCardsClient.getTransaction(
id,
cachePolicy = CachePolicy.REMOTE_ONLY
)
}
// If the [id] matches a transaction, [transaction] will be returned, else [null]
} catch (e: TransactionException) {
// Handle/notify user of exception
}
}

Multiple Transactions

The ability to retrieve multiple transactions available to the user is supported. These results can be paginated and can contain transactions in various states.
A call to a list API will return a ListTransactionsResult with a status and depending on the status, a list of matching items and a nextToken to support pagination. If no results matching the input are found, the result will contain empty items. There can be three possible statuses returned:
Status
Definition
Success
A list of all requested transactions are returned.
Partial
A list of all transactions that were successfully fetched and decrypted are returned as well as a list of all transactions that failed to decrypt successfully, including an error indicating the reason for the failure.
Failure
All transactions failed to be fetched or decrypted. Contains an error indicating the reason for the failure.
A transaction may fail to be unencrypted if the version of the client is not up-to-date or if the required cryptographic key is missing from the client device.

All Transactions for a Virtual Card

To retrieve multiple transactions that are associated with a certain virtual card, call the listTransactionsByCardId method by passing in the id of the virtual card to query. An optional sortOrder and dateRange can also be supplied to organise results.
TypeScript
Swift
Kotlin
// Collect the input virtual card id however makes sense for your implementation.
const virtualCardId = virtualCard.id
try {
const result = await virtualCardsClient.listTransactionsByCardId({
virtualCardId,
cachePolicy: CachePolicy.RemoteOnly,
limit: 20,
nextToken
})
if (result.status === ListOperationResultStatus.Success) {
// `result.items` contains the list of items matching the input.
// Page through the results if result.nextToken != undefined.
} else if (result.status === ListOperationResultStatus.Partial) {
// `result.items` contains the list of items matching the input that decrypted successfully.
// `result.failed` contains the list of items that failed decryption with associated error.
// Page through the results if `partial.nextToken` != undefined.
} else {
// `result.clause` contains the error which caused the failure.
}
} catch {
// Handle/notify user of errors
}
// Collect the input virtual card id however makes sense for your implementation.
do {
let result = try await self.virtualCardsClient.listTransactions(
withCardId: "id-of-card",
nextToken: nil,
dateRange: nil,
sortOrder: nil,
cachePolicy: .remoteOnly
)
switch result {
case .success(let output):
// `output.items` contains the list of items matching the input.
// Page through the results if `output.nextToken` != nil.
case .partial(let partial):
// `partial.items` contains the list of items matching the input that decrypted successfully.
// `partial.failed` contains the list of items that failed decryption with associated error.
// Page through the results if `partial.nextToken` != nil.
} catch {
// Handle/notify user of error
}
// Collect the input virtual card id however makes sense for your implementation.
// val virtualCardId = virtualCard.id
launch {
try {
val result = withContext(Dispatchers.IO) {
virtualCardsClient.listTransactions(
cardId = virtualCardId
limit = 20,
nextToken = null,
cachePolicy = CachePolicy.REMOTE_ONLY,
dateRange = null,
sortOrder = SortOrder.DESC
)
}
when (result) {
is ListAPIResult.Success -> {
// [result.items] contains the list of items matching the input.
// Page through the results if [output.nextToken] != null.
}
is ListAPIResult.Partial -> {
// [result.items] contains the list of items matching the input that decrypted successfully.
// [result.failed] contains the list of items that failed decryption with associated error.
// Page through the results if [partial.nextToken] != null.
}
}
} catch (e: TransactionException) {
// Handle/notify user of exception
}
}

All Transactions for a User

To retrieve multiple transactions that are associated across all of a user's virtual cards, call the listTransactions method. An optional sortOrder and dateRange can also be supplied to organise results.
TypeScript
Swift
Kotlin
try {
const result = await virtualCardsClient.listTransactions({
cachePolicy: CachePolicy.RemoteOnly,
limit: 20,
nextToken,
dateRange,
sortOrder: SortOrder.ascending
})
if (result.status === ListOperationResultStatus.Success) {
// `result.items` contains the list of items matching the input.
// Page through the results if result.nextToken != undefined.
} else if (result.status === ListOperationResultStatus.Partial) {
// `result.items` contains the list of items matching the input that decrypted successfully.
// `result.failed` contains the list of items that failed decryption with associated error.
// Page through the results if `partial.nextToken` != undefined.
} else {
// `result.clause` contains the error which caused the failure.
}
} catch {
// Handle/notify user of errors
}
do {
let result = try await self.virtualCardsClient.listTransactions(
nextToken: nil,
dateRange: dateRange,
sortOrder: SortOrder.ascending,
cachePolicy: .remoteOnly
)
switch result {
case .success(let output):
// `output.items` contains the list of items matching the input.
// Page through the results if `output.nextToken` != nil.
case .partial(let partial):
// `partial.items` contains the list of items matching the input that decrypted successfully.
// `partial.failed` contains the list of items that failed decryption with associated error.
// Page through the results if `partial.nextToken` != nil.
} catch {
// Handle/notify user of error
}
launch {
try {
val result = withContext(Dispatchers.IO) {
virtualCardsClient.listTransactions(
limit = 20,
nextToken = null,
cachePolicy = CachePolicy.REMOTE_ONLY,
dateRange = null,
sortOrder = SortOrder.DESC
)
}
when (result) {
is ListAPIResult.Success -> {
// [result.items] contains the list of items matching the input.
// Page through the results if [output.nextToken] != null.
}
is ListAPIResult.Partial -> {
// [result.items] contains the list of items matching the input that decrypted successfully.
// [result.failed] contains the list of items that failed decryption with associated error.
// Page through the results if [partial.nextToken] != null.
}
}
} catch (e: TransactionException) {
// Handle/notify user of exception
}
}

Subscribing to Transactions

Typescript Libraries currently do not support subscribing to transactions.
You can subscribe to receive updates as transactions are created, updated and deleted. The subscribeToTransactions, unsubscribeFromTransactions and unsubscribeAll APIs allow you to start and stop receiving updates.
You may receive multiple updates for a single transaction over time. Each time the transaction changes you will receive a new update. You should receive an update when the transaction is first created, the type field of the transaction will be PENDING. Some time later you will receive another update with the type set to COMPLETE, REFUND or DECLINE.
Swift
Kotlin
do {
let subscriptionToken = try await client.subscribeToTransactionUpdates(
statusChangeHandler: { status in
/// Handle status changes
},
resultHandler: { result in
switch result {
case let .success(transaction):
/// Transaction update event occurred.
case let .failure(error):
}
)
} catch {
/// Error occurred while receiving transaction update.
}
val subscriptionId = UUID.randomUUID().toString()
launch {
try {
withContext(Dispatchers.IO) {
virtualCardsClient.subscribeToTransactions(subscriptionId) { txn ->
// Handle updated transaction
}
}
} catch (e: TransactionException) {
// Handle exception
}
// Some time later ...
withContext(Dispatchers.IO) {
virtualCardsClient.unsubscribeFromTransactions(subscriptionId)
}
}