Match Transactions to Receipts
What is Transaction Matching?
Transaction Matching occurs when a receipt is matched to a transaction from an external system. The match is performed based on the amount, date and currency.
When matched to a receipt the property TransactionID is updated on the receipt. This can then be used to display/show the details of a receipt previously matched to a specific transaction. When performing a transaction matching query, it is possible that more than one receipt may be returned as a potential match.
Info
Types of matching
Date Match
An ExternalAccountTransaction
has two potential dates:
date
: The date the transaction occurred- Takes priority over
ExternalAccountTransaction.postedDate
- If not present, the
postedDate
will be used
- Takes priority over
postedDate
: The date the transaction was posted to the bank account- In cases where only the
postedDate
is available do not set thedate
- In cases where only the
The matcher will check if the date is within a certain time range of the receipt
- For
ExternalAccountTransaction.date
, receipts can be considered potential matches if the receipt date is within 1 day (before/after) of the transaction date - For
ExternalAccountTransaction.postedDate
, receipts can be considered potential matches if the receipt date is within 3 days before, or one day after the posted date
Currency Match
A receipt will be considered a potential match if the currency code set on the ExternalAccountTransaction
matches the currency code on the receipt.
Amount Match
A receipt will be considered a potential match if the amount set on the ExternalAccountTransaction
matches the amount on the receipt.
If these three properties match, the receipt will be linked to matching transaction. The matcher first attempts to match explicitly and then if not, implicitly. Transactions can only be matched to one receipt.
- Create an array of
SBExternalAccountTransaction
objects that represent bank account transactions you want to match. - Call
SensibillTransactionMatcher.sharedInstance().receipts
. This function is asynchronous. As an input, provide a created array and a callback to be executed when the matching results are ready 3. Inside the callback, verify if an error was returned first. If not, parse the results. Results are provided in the format[SBExternalAccountTransaction: SBReceipt?]
Notes:
- The bare minimum required fields are: amount, currency, and date.
- The more fields that are set on an
SBExternalAccountTransaction
object, the more likely we are to make a unique match. - To help the matcher filter banking transactions that have already been linked with receipts using Transaction Linking
, set the
SBExternalAccountTransaction.transactionID
field.
Example: Matching a bank transaction
A few examples below show various fields supplied for matching.
Note that SBExternalAccountTransaction
is optional and needs to be unwrapped.
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
// With minimum information
guard let t1 = SBExternalAccountTransaction(
amount: 3.15,
currencyCode: .CAD,
date: dateFormatter.date(from: "2020-05-22")) else {
// Failed to create banking transaction match
return
}
// Already matched with Transaction Linking
guard let t2 = SBExternalAccountTransaction(
amount: 15.33,
currencyCode: .CAD,
date: dateFormatter.date(from: "2020-04-11"),
transactionID: "SOMEID584937594792",
postedDate: nil, summary: "", maskedAccountNumber: "", merchantName: "") else {
// Failed to create banking transaction match
return
}
// With more information, not linked with Transaction Linking
guard let t3 = SBExternalAccountTransaction(
amount: 2.93,
currencyCode: .CAD,
date: dateFormatter.date(from: "2020-06-01"),
transactionID: nil,
postedDate: dateFormatter.date(from: "2018-05-22"),
summary: "",
maskedAccountNumber: "************6789",
merchantName: "Awesome Coffee") else {
// Failed to create banking transaction match
return
}
Calling Transaction Matcher
Once you have identified all the transactions you want to match, you can call the transaction matcher.
The following example uses transactions created in the previous step and verifies if a match for transaction t1
was found.
SensibillTransactionMatcher.sharedInstance().receipts(for: [ t1, t2, t3 ]) { (matches, error) in
guard error == nil else {
// There's an error
return
}
guard let matches = matches else {
// Failed to unwrap matches
return
}
if let receipt = matches[t1] as? SBReceipt {
// Match found for transaction t1
// We can check receipt id for example
let receiptId = receipt.id
} else {
// No match found for transaction t1
}
}
The externalTransactionID can then saved against SBReceipt using external private meta data.
1. Create a List of ExternalAccountTransaction
s
Create a list of transactions for which you wish to match receipts to.
Given any number of external account transactions, for which definitions can be variable, extract the necessary information from the transaction model to fill a Sensibill ExternalAccountTransaction
object. The ExternalAccountTransaction
acts as a bridge between the client and the Sensibill SDK.
The TransactionBuilder
class can be used to help construct ExternalAccountTransaction
s.
Kotlin
val myTransaction: MyTransactionModel // Your transaction model
val mySecondTransaction: MyTransactionModel
val transactionList: List<ExternalAccountTransaction> = listOf(
TransactionBuilder()
.id(myTransaction.id)
.metaDataWithDate(
myTransaction.date,
myTransaction.amount,
myTransaction.currencyCode
).build(),
TransactionBuilder()
.id(mySecondTransaction.id)
.metaDataWithDate(
mySecondTransaction.date,
mySecondTransaction.amount,
mySecondTransaction.currencyCode
).build(),
)
Java
final MyTransactionModel myTransaction; // Your transaction model
final MyTransactionModel mySecondTransaction;
final ArrayList<ExternalAccountTransaction> transactionList = new ArrayList<>();
transactionList.add(
new TransactionBuilder()
.id(myTransaction.getId())
.metaDataWithDate(
myTransaction.getDate(),
myTransaction.getAmount(),
myTransaction.getCurrencyCode()
)
.build()
);
transactionList.add(
new TransactionBuilder()
.id(mySecondTransaction.getId())
.metaDataWithDate(
mySecondTransaction.getDate(),
mySecondTransaction.getAmount(),
mySecondTransaction.getCurrencyCode()
)
.build()
);
Reference ExternalAccountTransactionTransactionBuilder
2. Create a TransactionMatcher
Using TransactionMatcherBuilder
Next, a TransactionMatcher
must be created. This can be done with the help of TransacitonMatcherBuilder
.
Note: In order to create a TransactionMatcher
, you will need a reference to a valid user accessToken
for the Sensibill APIs. This can either be retrieved from your integration server if using Custom Token Provider Authentication, or from SensibillAuth
if using Password Authentication
Kotlin
val transactionMatcher: TransactionMatcher = TransactionMatcherBuilder(
applicationContext,
DefaultEnvironment.RECEIPTS_SANDBOX,
"accessToken"
).build()
Java
final TransactionMatcher transactionMatcher = new TransactionMatcherBuilder(
getApplicationContext(),
DefaultEnvironment.RECEIPTS_SANDBOX,
"accessToken"
).build();
Reference TransactionMatcherBuilderPassword AuthenticaitonCustom Token Provider Authentication
3. Search for Matching Receipts With .matchTransaction()
Once you’ve built a TransactionMatcher
, it can then be used to look for receipts matching each transaction in the list of ExternalAccountTransaction
s created earlier.
Kotlin
transactionMatcher.matchTransaction(transactionList, object : TransactionMatcher.TransactionMatcherListener {
override fun onMatched(transactionList: MutableList<MatchedExternalAccountTransaction>?) {
// Handle the `TransactionMatcher` successfully finding matching receipts
}
override fun onMatched(map: MutableMap<ExternalAccountTransaction, MatchedReceiptInfo>?) { /* Deprecated */ }
override fun hasFailed(errorCode: Int, message: String?) {
// Handle the `TransactionMatcher` failing to find matching receipts
}
})
Java
transactionMatcher.matchTransaction(transactionList, new TransactionMatcher.TransactionMatcherListener() {
@Override
public void onMatched(List<MatchedExternalAccountTransaction> transactionList) {
// Handle the `TransactionMatcher` successfully finding matching receipts
}
@Override
public void onMatched(Map<ExternalAccountTransaction, MatchedReceiptInfo> map) { /* Deprecated */ }
@Override
public void hasFailed(int errorCode, String message) {
// Handle the `TransactionMatcher` failing to find matching receipts
}
});
Reference TransactionMatcherMatchedExternalAccountTransaction
4. Handle Found Matches
Upon finding matches, the TransactionMatcher
will provide a List
of MatchedExternalAccountTransaction
objects to the onMatched
method provided in the TransactionMatcherListener
.
Each MatchedExternalAccountTransaction
contains the original information from the ExternalAccountTransaction
that was provided, as well as a MatchedReceiptInfo
attachment, accessible by .receipt
(.getReceipt()
in Java).
Any desired infromation about the matched receipt can then be extraced from the MatchedReceiptInfo
.
Of particular use is the .id
(.getId()
in Java) property, which can be used to retrieve the receiptId
of the matched receipt. This can then be saved for later in order to recall matched receipts on demand.
Reference MatchedExternalAccountTransactionMatchedReceiptInfo