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.

Info

When performing a transaction matching query, it is possible that more than one receipt may be returned as a potential match.

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
  • postedDate: The date the transaction was posted to the bank account
    • In cases where only the postedDate is available do not set the date

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.

  1. Create an array of SBExternalAccountTransaction objects that represent bank account transactions you want to match.
  2. 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 ExternalAccountTransactions

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 ExternalAccountTransactions.

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 ExternalAccountTransaction
TransactionBuilder

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 TransactionMatcherBuilder
Password Authenticaiton
Custom 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 ExternalAccountTransactions 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 TransactionMatcher
MatchedExternalAccountTransaction

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 MatchedExternalAccountTransaction
MatchedReceiptInfo