Skip to main content

Record invoice finance repayments

Record the repayment of money owed to the lender for an invoice financing loan in the SMB's accounting platform

Once the borrower's customer has paid for the goods or services they purchased, the financed invoice is ready to be reconciled in the accounting platform.

To reflect that programmatically, perform these steps:

  1. Create a transfer from the lender's bank account to the borrower's to account for the oustanding amount less fees.

  2. To record interest or fees, create a direct cost against the lender's bank account.

  3. To update the invoice as paid, create a payment in the lender's bank account.

  4. Create bank feed transactions to represent the transfer, direct cost and invoice payment in the lender's bank account.

To perform these operations, you will need the following properties:

Create transfer

Once the SMB's customer pays the invoice, use the Create transfer endpoint to record the outstanding amount not covered by the loan. Note that you are performing a transfer from lendersBankAccount.id to borrowersBankAccount.id.

The amount outstanding is calculated as:

outstandingAmount = invoiceAmount - advanceAmount - feeAndInterestAmount

Store outstandingAmount and outstandingAmountTransferDate in your application for use later on.

codatLending.loanWriteback.transfers.create({
accountingTransfer: {
date: outstandingAmountTransferDate,
from: {
accountRef: {
id: lendersBankAccount.id,
},
amount: outstandingAmount,
currency: borrowersBankAccount.currency,
},
to: {
accountRef: {
id: borrowersBankAccount.id,
},
amount: outstandingAmount,
currency: borrowersBankAccount.currency,
},
},
companyId: "8a210b68-6988-11ed-a1eb-0242ac120002",
connectionId: "2e9d2c44-f675-40ba-8049-353bfcb5e171",
}).then((res: CreateTransferResponse) => {
if (res.statusCode == 200) {
// handle response
}
});

Create direct cost

Check the Get create direct cost model, then use the Create direct cost endpoint to capture the amount of fees or interest (feeAndInterestAmount) incurred by the borrower.

Store the feeAndInterestAmount and the direct cost's issueDate for use later on in your application.

codatLending.loanWriteback.directCosts.create({
accountingDirectCost: {
contactRef: {
dataType: "suppliers",
id: supplier.id,
},
currency: borrowersBankAccount.currency,
issueDate: feeAndInterestIssueDate,
lineItems: [
{
accountRef: {
id: expenseAccount.id,
},
description: "Fees and/or interest",
quantity: 1,
taxAmount: 0,
unitAmount: feeAndInterestAmount,
},
],
paymentAllocations: [
{
allocation: {
totalAmount: feeAndInterestAmount,
},
payment: {
accountRef: {
id: lendersBankAccount.id,
},
},
},
],
taxAmount: 0.0,
totalAmount: feeAndInterestAmount,
},
companyId: "8a210b68-6988-11ed-a1eb-0242ac120002",
connectionId: "2e9d2c44-f675-40ba-8049-353bfcb5e171",
}).then((res: CreateDirectCostResponse) => {
if (res.statusCode == 200) {
// handle response
}
});

Create payment

Next, use the Create payment endpoint to acknowledge payment has been received for the invoice. Store the invoicePaymentDate for use later on in your application.

sdk.loanWriteback.payments.create({
accountingPayment: {
accountRef: {
id: lendersBankAccount.id,
},
currency: borrowersBankAccount.Currency,
customerRef: {
id: invoice.customerRef.id,
},
date: invoicePaymentDate,
lines: [
{
allocatedOnDate: invoicePaymentDate,
amount: invoice.totalAmount, // The sum of the link amounts plus the line amount must equal zero
links: [
{
amount: -invoice.totalAmount, // Note the negative sign is here
currencyRate: 1,
id: invoice.id,
type: PaymentLinkType.Invoice,
},
],
},
],
totalAmount: invoice.totalAmount,
},
companyId: "8a210b68-6988-11ed-a1eb-0242ac120002",
connectionId: "2e9d2c44-f675-40ba-8049-353bfcb5e171",
}).then((res: CreatePaymentResponse) => {
if (res.statusCode == 200) {
// handle response
}
});

Create bank feed transactions

Finally, use the Create bank account transactions endpoint again to deposit the total amount (including the repayment, fees, and any interest) into the lender's bank account. You will need the previously stored values for this operation.

codatLending.loanWriteback.bankTransactions.create({
accountingCreateBankTransactions: {
accountId: lendersBankAccount.id, // Lender's virtual bank account ID you would have stored from the configuration step
transactions: [
{
id: transactionId, // Unique identifier for this bank transaction
amount: feeAndInterestAmount,
date: feeAndInterestIssueDate,
description: description, // Include a reference to supplier and direct cost
},
{
id: transactionId, // Unique identifier for this bank transaction
amount: outstandingAmount,
date: outstandingAmountTransferDate,
description: description, // Include a reference to transfer
},
{
id: transactionId, // Unique identifier for this bank transaction
amount: invoice.totalAmount,
date: invoicePaymentDate,
description: description, // Include a reference to the customer and invoice number/ID
},
],
},
accountId: lendersBankAccount.Id,
companyId: "8a210b68-6988-11ed-a1eb-0242ac120002",
connectionId: "2e9d2c44-f675-40ba-8049-353bfcb5e171",
}).then((res: CreateBankTransactionsResponse) => {
if (res.statusCode == 200) {
// handle response
}
});

At the end of this 3-stage process, your borrower will have the loan writeback reflected correctly in their accounting platform. This saves them time on reconciliation and makes sure they (and you!) have clarity on the state of the loan.

Recap

In this guide, you have learned:

  • What is loan writeback and what it's used for.
  • How to map and configure the loan writeback solution.
  • How to perform the necessary postings using Codat's endpoints.


Was this page useful?
❤️
👍
🤔
👎
😭