diff --git a/docs/bank-feeds/create-account.md b/docs/bank-feeds/create-account.md index 36abd723b..544cd73e3 100644 --- a/docs/bank-feeds/create-account.md +++ b/docs/bank-feeds/create-account.md @@ -341,7 +341,7 @@ const sourceAccountResponse = bankFeedsClient.sourceAccounts.create({ sourceAccount: { id: "ac-001", accountName: "Checking Account", - accountType: "Debit", + accountType: "checking", accountNumber: "01120912", currency: "USD", balance: 4002 @@ -359,7 +359,7 @@ const sourceAccountResponse = bankFeedsClient.sourceAccounts.create({ source_account_request = operations.CreateSourceAccountRequest( id="ac-001", accountName="Checking Account", - accountType="Debit", + accountType=AccountType.CHECKING, accountNumber="01120912", currency="USD", balance=4002 @@ -380,7 +380,7 @@ var sourceAccountResponse = await bankFeedsClient.SourceAccounts.CreateAsync(new SourceAccount = new SourceAccount() { Id = "ac-001", AccountName = "Checking Account", - AccountType = "Debit", + AccountType = AccountType.Checking, AccountNumber = "01120912", Currency = "USD", Balance = 4002 @@ -401,7 +401,7 @@ sourceAccountResponse, err := bankFeedsClient.SourceAccounts.Create(ctx, operati SourceAccount: &shared.SourceAccount{ ID: bankfeeds.String("ac-001"), AccountName: bankfeeds.String("Checking Account"), - AccountType: bankfeeds.String("Debit"), + AccountType: shared.AccountTypeChecking, AccountNumber: bankfeeds.String("01120912"), Currency: bankfeeds.String("USD"), Balance: 4002 @@ -412,6 +412,29 @@ sourceAccountResponse, err := bankFeedsClient.SourceAccounts.Create(ctx, operati ``` + + +```java +CreateSourceAccountRequest req = CreateSourceAccountRequest.builder() + .requestBody(CreateSourceAccountRequestBody.of(SourceAccountV2.builder() + .id("ac-001") + .accountName("Checking Account") + .accountType(AccountType.LOAN) + .accountNumber("01120912") + .currency("USD") + .balance(new BigDecimal("4002")) + .build())) + .companyId(companyId) + .connectionId(connectionId) + .build(); + +CreateSourceAccountResponse res = bankFeedsClient.sourceAccounts().create() + .request(req) + .call(); +``` + + + Once the source account is successfully created, guide your customer through the **mapping process** to associate it with a corresponding target account in their accounting software. The account will stay in a `pending` status until that happens, and it must change to `linked` before you can successfully transmit any bank transactions. @@ -433,7 +456,7 @@ const sourceAccountUpdateResponse = bankFeedsClient.sourceAccounts.update({ sourceAccount: { id: "ac-001", accountName: "Bank of Dave Checking Account", - accountType: "Debit", + accountType: "checking", accountNumber: "01120912", currency: "USD", balance: 4002 @@ -454,7 +477,7 @@ source_account_update_request = operations.UpdateSourceAccountRequest( source_account=shared.SourceAccount( id="ac-001", accountName="Bank of Dave Checking Account", - accountType="Debit", + accountType=AccountType.CHECKING, accountNumber="01120912", currency="USD", balance=4002 @@ -476,7 +499,7 @@ var sourceAccountUpdateResponse = await sdk.SourceAccounts.UpdateAsync(new() { SourceAccount = new SourceAccount() { Id = "ac-001", AccountName = "Checking Account", - AccountType = "Debit", + AccountType = AccountType.Checking, AccountNumber = "01120912", Currency = "USD", Balance = 4002 @@ -497,7 +520,7 @@ res, err := bankFeedsClient.SourceAccounts.Update(ctx, operations.UpdateSourceAc SourceAccount: &shared.SourceAccount{ ID: bankfeeds.String("ac-001"), AccountName: bankfeeds.String("Checking Account"), - AccountType: bankfeeds.String("Debit"), + AccountType: shared.AccountTypeChecking, AccountNumber: bankfeeds.String("01120912"), Currency: bankfeeds.String("USD"), Balance: 4002 diff --git a/docs/lending/guides/invoice-finance/introduction.md b/docs/lending/guides/invoice-finance/introduction.md index 5bfd571bf..159cf74d6 100644 --- a/docs/lending/guides/invoice-finance/introduction.md +++ b/docs/lending/guides/invoice-finance/introduction.md @@ -35,7 +35,7 @@ This guide is for tech-savvy backend developers who know how to use an API. No f - Building any application form or dashboard UIs - Carrying out due diligence checks on the borrower - Instructions on how to build your own invoice financing product -- Details on how to perform [loan writeback](/lending/guides/loan-writeback/introduction) for invoice financing [(see also: Record invoice finance repayments)](/lending/guides/loan-writeback/record-invoice-finance) +- Details on how to perform [loan writeback](/lending/guides/loan-writeback/introduction) for invoice financing ### About the demo app diff --git a/docs/lending/guides/loan-writeback/configure.md b/docs/lending/guides/loan-writeback/configure.md index 48cea4063..89dbdf1cf 100644 --- a/docs/lending/guides/loan-writeback/configure.md +++ b/docs/lending/guides/loan-writeback/configure.md @@ -14,7 +14,8 @@ Once your SMB customer's loan has been approved, provide them with a user interf * **Expense account**, an account to record incurred fees and interest. * **Supplier record**, a record to identify you, the lender, in future transactions. -Your solution also needs a **lender bank account**, a virtual account that contains the lender's transactions. You would have created this source account when implementing [bank feeds](/bank-feeds/overview). Now, map it to a target account in your SMB customer's accounting software. You can define it as `lendersBankAccount` in your solution. +Your solution also requires a **lender bank account** - a virtual account that contains the lender's transactions. +This account, also known as a container, clearing, or drawdown account, is used to manage and track funds related to lending activities. :::info Let your customers take control @@ -22,7 +23,6 @@ In some cases, the SMB's bookkeeper will want to manage their accounts themselve ::: - For example, your user interface might look something like this: @@ -35,7 +35,6 @@ sequenceDiagram participant backend as Your application participant codat as Codat - frontend ->> backend: Configures writeback backend ->> codat: List suppliers @@ -62,13 +61,19 @@ sequenceDiagram end backend -->> frontend: View configuration + + backend -->> codat: Create source account + codat -->> backend: Source account + + backend -->> codat: Map source account + codat -->> backend: Mapped source account ``` ### Bank account -Loan writeback process operates with two bank accounts: +The loan writeback process uses two bank accounts: - A borrower's business bank account where the money lent is deposited. -- A lender's bank account, which is a virtual bank account in the accounting software that acts as a container for lender transactions. +- A lender's bank account, which is a virtual account in the accounting software that serves as a container for lender transactions. This account is created when [setting up the bank feed source account](#bank-feed-source-account). First, your customer needs to choose one of their existing business bank accounts. This account will be used to depost the loan. Call our [List bank accounts](/lending-api#/operations/list-accounting-bank-accounts) endpoint to retrieve the customer's existing bank accounts. @@ -77,8 +82,8 @@ First, your customer needs to choose one of their existing business bank account ```javascript codatLending.accountingBankData.accounts.list({ - companyId: "8a210b68-6988-11ed-a1eb-0242ac120002", - connectionId: "2e9d2c44-f675-40ba-8049-353bfcb5e171" + companyId: companyId, + connectionId: connectionId }).then((res: ListAccountingBankAccountsResponse) => { if (res.statusCode == 200) { // handle response @@ -91,8 +96,8 @@ if (res.statusCode == 200) { ```python bank_accounts_list_request = operations.ListAccountingBankAccountsRequest( - company_id='8a210b68-6988-11ed-a1eb-0242ac120002', - connection_id='2e9d2c44-f675-40ba-8049-353bfcb5e171' + company_id=company_id, + connection_id=connection_id ) bank_accounts_list_response = codat_lending.accounting_bank_data.accounts.list(bank_accounts_list_request) @@ -103,8 +108,8 @@ bank_accounts_list_response = codat_lending.accounting_bank_data.accounts.list(b ```csharp var bankAccountsListResponse = await codatLending.AccountingBankData.Accounts.ListAsync(new ListAccountingBankAccountsRequest() { - CompanyId = "8a210b68-6988-11ed-a1eb-0242ac120002", - ConnectionId = "2e9d2c44-f675-40ba-8049-353bfcb5e171" + CompanyId = companyId, + ConnectionId = connectionId }); ``` @@ -116,8 +121,8 @@ ctx := context.Background() bankAccountsListResponse, err := codatLending.AccountingBankData.Accounts.List( ctx, operations.ListAccountingBankAccountsRequest{ - CompanyID: "8a210b68-6988-11ed-a1eb-0242ac120002", - ConnectionID: "2e9d2c44-f675-40ba-8049-353bfcb5e171", + CompanyID: companyID, + ConnectionID: connectionID, }) ``` @@ -133,8 +138,6 @@ GET https://api.codat.io/companies/{companyId}/connections/{connectionId}/data/b Display the response to the customer and allow them to select the account. Store the returned bank account as `borrowersBankAccount` and use it to access properties on the borrower's bank account in future operations. -For the lender's bank account, use the `lendersBankAccount` value you would have created when implementing [bank feeds](../../../terms/bank-feed). - ### Supplier In order to create a *spend money* transaction, Codat requires you, the lender, to be represented as a [supplier](../../../terms/supplier) in your SMB's accounting system. @@ -146,7 +149,7 @@ Let your customer check if your record already exists in their accounts. Use our ```javascript codatLending.accountsPayable.suppliers.list({ - companyId: "8a210b68-6988-11ed-a1eb-0242ac120002", + companyId: companyId, }).then((res: ListAccountingSuppliersResponse) => { if (res.statusCode == 200) { // handle response @@ -159,7 +162,7 @@ if (res.statusCode == 200) { ```python suppliers_list_request = operations.ListAccountingSuppliersRequest( - company_id='8a210b68-6988-11ed-a1eb-0242ac120002', + company_id=company_id, ) suppliers_list_response = codat_lending.accounts_payable.suppliers.list(suppliers_list_request) @@ -170,7 +173,7 @@ suppliers_list_response = codat_lending.accounts_payable.suppliers.list(supplier ```csharp var suppliersListResponse = await codatLending.AccountsPayable.Suppliers.ListAsync(new ListAccountingSuppliersRequest() { - CompanyId = "8a210b68-6988-11ed-a1eb-0242ac120002" + CompanyId = companyId }); ``` @@ -180,7 +183,7 @@ var suppliersListResponse = await codatLending.AccountsPayable.Suppliers.ListAsy ```go ctx := context.Background() suppliersListResponse, err := codatLending.AccountsPayable.Suppliers.List(ctx, operations.ListAccountingSuppliersRequest{ - CompanyID: "8a210b68-6988-11ed-a1eb-0242ac120002" + CompanyID: companyID }) ``` @@ -224,8 +227,8 @@ codatLending.loanWriteback.suppliers.create({ status: SupplierStatus.Active, supplierName: "Bank of Dave", }, - companyId: "8a210b68-6988-11ed-a1eb-0242ac120002", - connectionId: "2e9d2c44-f675-40ba-8049-353bfcb5e171", + companyId: companyId, + connectionId: connectionId, }).then((res: CreateSupplierResponse) => { if (res.statusCode == 200) { // handle response @@ -256,8 +259,8 @@ supplier_create_request = operations.CreateSupplierRequest( status=shared.SupplierStatus.ACTIVE, supplier_name='Bank of Dave', ), - company_id='8a210b68-6988-11ed-a1eb-0242ac120002', - connection_id='2e9d2c44-f675-40ba-8049-353bfcb5e171', + company_id=company_id, + connection_id=connection_id, ) supplier_create_response = codat_lending.loan_writeback.suppliers.create(supplier_create_request) @@ -286,8 +289,8 @@ var suppliersCreateResponse = await codatLending.LoanWriteback.Suppliers.CreateA Status = CodatLending.Models.Shared.SupplierStatus.Active, SupplierName = "Bank of Dave", }, - CompanyId = "8a210b68-6988-11ed-a1eb-0242ac120002", - ConnectionId = "2e9d2c44-f675-40ba-8049-353bfcb5e171", + CompanyId = companyId, + ConnectionId = connectionId, }); ``` @@ -315,8 +318,8 @@ suppliersCreateResponse, err := codatLending.LoanWriteback.Suppliers.Create(ctx, Status: shared.SupplierStatusActive, SupplierName: lending.String("Bank of Dave"), }, - CompanyID: "8a210b68-6988-11ed-a1eb-0242ac120002", - ConnectionID: "2e9d2c44-f675-40ba-8049-353bfcb5e171", + CompanyID: companyID, + ConnectionID: connectionID, }) ``` @@ -356,14 +359,14 @@ Similarly, store the `supplier` and use it in future transactions. ### Expense account -Finally, use our [List accounts](/lending-api#/operations/list-accounting-accounts) endpoint filtered by `type=Expense` to retrieve the customer's existing expense accounts. Let them choose one that will be used to record fees and interest. +Next, use our [List accounts](/lending-api#/operations/list-accounting-accounts) endpoint filtered by `type=Expense` to retrieve the customer's existing expense accounts. Let them choose one that will be used to record fees and interest. ```javascript codatLending.financialStatements.accounts.list({ - companyId: "8a210b68-6988-11ed-a1eb-0242ac120002", + companyId: companyId, query: "type=Expense", }).then((res: ListAccountingAccountsResponse) => { if (res.statusCode == 200) { @@ -377,7 +380,7 @@ if (res.statusCode == 200) { ```python accounts_list_request = operations.ListAccountingAccountsRequest( - company_id='8a210b68-6988-11ed-a1eb-0242ac120002', + company_id=company_id, query='type=Expense', ) @@ -389,7 +392,7 @@ accounts_list_response = codat_lending.financial_statements.accounts.list(accoun ```csharp var accountsListResponse = await codatLending.FinancialStatements.Accounts.ListAsync(new ListAccountingAccountsRequest() { - CompanyId = "8a210b68-6988-11ed-a1eb-0242ac120002", + CompanyId = companyId, Query = "type=Expense", }); ``` @@ -400,7 +403,7 @@ var accountsListResponse = await codatLending.FinancialStatements.Accounts.ListA ```go ctx := context.Background() accountsListResponse, err := codatLending.FinancialStatements.Accounts.List(ctx, operations.ListAccountingAccountsRequest{ - CompanyID: "8a210b68-6988-11ed-a1eb-0242ac120002", + CompanyID: companyId, Query: lending.String("type=Expense"), }) ``` @@ -438,8 +441,8 @@ accountingAccount: { type: AccountType.Asset, }, -companyId: "8a210b68-6988-11ed-a1eb-0242ac120002", -connectionId: "2e9d2c44-f675-40ba-8049-353bfcb5e171", +companyId: companyId, +connectionId: connectionId, }).then((res: CreateAccountResponse) => { if (res.statusCode == 200) { // handle response @@ -463,8 +466,8 @@ accounts_create_request = operations.CreateAccountRequest( status=shared.AccountStatus.ACTIVE, type=shared.AccountType.ASSET, ), - company_id='8a210b68-6988-11ed-a1eb-0242ac120002', - connection_id='2e9d2c44-f675-40ba-8049-353bfcb5e171', + company_id=company_id, + connection_id=connection_id, ) accounts_create_response = codat_lending.loan_writeback.accounts.create(accounts_create_request) @@ -486,8 +489,8 @@ var accountsCreateResponse = await codatLending.LoanWriteback.Accounts.CreateAsy Status = CodatLending.Models.Shared.AccountStatus.Active, Type = CodatLending.Models.Shared.AccountType.Asset }, - CompanyId = "8a210b68-6988-11ed-a1eb-0242ac120002", - ConnectionId = "2e9d2c44-f675-40ba-8049-353bfcb5e171", + CompanyId = companyId, + ConnectionId = connectionId, }); ``` @@ -508,8 +511,8 @@ accountsCreateResponse, err := codatLending.LoanWriteback.Accounts.Create(ctx, o Status: shared.AccountStatusActive.ToPointer(), Type: shared.AccountTypeAsset.ToPointer(), }, - CompanyID: "8a210b68-6988-11ed-a1eb-0242ac120002", - ConnectionID: "2e9d2c44-f675-40ba-8049-353bfcb5e171" + CompanyID: companyID, + ConnectionID: connectionID }) ``` @@ -541,8 +544,217 @@ POST https://api.codat.io/companies/{companyId}/connections/{connectionId}/push/ In response, you will receive account creation details which you can display to your customer. Similarly, store the account as `expenseAccount` for use in future transactions. +### Bank feed source account + +Finally, create and map a source account to enable the flow of bank transactions that the SMB can reconcile in their accounting software. This two-step process establishes the lender’s bank account, defined as `lendersBankAccountId`, in your solution. + +#### Create source account + +Use the [Create source account](/lending-api#/operations/create-source-account) endpoint to create a representation of the lender's bank account within Codat's domain. The account must be in the loan's agreed currency. Ensure it has a zero balance and specify an ID and account number of your choice. For bank accounts in GBP, `sortCode` is also a required field. + + + + + +```javascript +const sourceAccountResponse = bankFeedsClient.sourceAccounts.create({ + sourceAccount: { + id: "bank-of-dave-lenders-account", + accountName: "Bank of Dave - loan account", + accountType: "loan", + accountNumber: "66260701", + currency: loanCurrency, + balance: 0.00 + }, + companyId: companyId, + connectionId: connectionId + }); + +const lendersBankAccountId = sourceAccountResponse.oneOf.sourceAccountV2.id; +``` + + + + + +```python +source_account_request = operations.CreateSourceAccountRequest( + id="bank-of-dave-lenders-account", + accountName="Bank of Dave - loan account", + accountType=AccountType.LOAN, + accountNumber="66260701", + currency=loan_currency, + balance=0.00 + ), + company_id=company_id, + connection_id=connection_id +) + +source_account_response = codatLending.source_accounts.create(req) + +lenders_bank_account_id = source_account_response.oneOf.sourceAccountV2.id +``` + + + + + +```csharp +var sourceAccountResponse = await codatLending.SourceAccounts.CreateAsync(new() { + SourceAccount = new SourceAccount() { + Id = "bank-of-dave-lenders-account", + AccountName = "Bank of Dave - loan account", + AccountType = AccountType.Loan, + AccountNumber = "66260701", + Currency = loanCurrency, + Balance = 0.00 + }, + CompanyId = companyId, + ConnectionId = connectionId +}); + +var lendersBankAccountId = sourceAccountResponse.OneOf.SourceAccountV2.Id; +``` + + + + + +```go +ctx := context.Background() +sourceAccountResponse, err := codatLending.LoanWriteback.SourceAccounts.Create(ctx, operations.CreateSourceAccountRequest{ + SourceAccount: &shared.SourceAccount{ + ID: lending.String("bank-of-dave-lenders-account"), + AccountName: lending.String("Bank of Dave - loan account"), + AccountType: shared.AccountTypeLoan, + AccountNumber: lending.String("66260701"), + Currency: lending.String(loanCurrency), + Balance: 0.00 + }, + CompanyID: companyID, + ConnectionID: connectionID +}) + +lendersBankAccountId := sourceAccountResponse.OneOf.SourceAccountV2.ID; +``` + + + + +```java +CreateSourceAccountRequest req = CreateSourceAccountRequest.builder() + .requestBody(CreateSourceAccountRequestBody.of(SourceAccountV2.builder() + .id("bank-of-dave-lenders-account") + .accountName("Bank of Dave - loan account") + .accountType(AccountType.LOAN) + .accountNumber("66260701") + .currency(loanCurrency) + .balance(new BigDecimal("0.00")) + .build())) + .companyId(companyId) + .connectionId(connectionId) + .build(); + +CreateSourceAccountResponse sourceAccountResponse = codatLending.loanWriteback() + .sourceAccounts() + .create() + .request(req) + .call(); + +String lendersBankAccountId = sourceAccountResponse.oneOf.sourceAccountV2.id; +``` + + + + + +#### Map source account + +To complete the setup, create a representation of the source account in the accounting software. Use the [Create bank feed account mapping](/lending-api#/operations/create-bank-account-mapping) endpoint to achieve this, mapping the source account without assigning a target account. This will create a target account automatically. + + + + + +```javascript +const mappingResponse = await codatLending.loanWriteback.sourceAccounts.createMapping({ + companyId: companyId, + connectionId: connectionId, + bankFeedBankAccountMapping: { + sourceAccountId: lendersBankAccountId, + }, + }); +``` + + + + + +```python +mapping_response = codat_lending.loan_writeback.source_accounts.create_mapping(request={ + "company_id": company_id, + "connection_id": connection_id, + "bank_feed_bank_account_mapping": { + "source_account_id": lenders_bank_account_id, + }, +}) +``` + + + + + +```csharp +var mappingResponse = await codatLending.LoanWriteback.SourceAccounts.CreateMappingAsync(new() { + CompanyId = companyId, + ConnectionId = connectionId, + BankFeedBankAccountMapping = new BankFeedBankAccountMapping() { + SourceAccountId = lendersBankAccountId, + }, +}); +``` + + + + + +```go +ctx := context.Background() +mappingResponse, err := codatLending.LoanWriteback.SourceAccounts.CreateMapping( + ctx, + operations.CreateBankAccountMappingRequest{ + CompanyID: companyID, + ConnectionID: connectionID, + BankFeedBankAccountMapping: &shared.BankFeedBankAccountMapping{ + SourceAccountID: lendersBankAccountID, + } + } +) +``` + + + + +```java +CreateBankAccountMappingRequest req = CreateBankAccountMappingRequest.builder() + .companyId(companyId) + .connectionId(connectionId) + .bankFeedBankAccountMapping(BankFeedBankAccountMapping.builder() + .sourceAccountId(sourceAccountResponse.oneOf().sourceAccountV2().Id) + .build()) + .build(); + +CreateBankAccountMappingResponse res = codatLending.loanWriteback().sourceAccounts().createMapping() + .request(req) + .call(); +``` + + + + + --- ## Read next -* Learn how to [deposit](/lending/guides/loan-writeback/deposit) the lent funds into your SMB's accounting software. \ No newline at end of file +* Learn how to [deposit](/lending/guides/loan-writeback/deposit) the lent funds into your SMB's accounting software. diff --git a/docs/lending/guides/loan-writeback/deposit.md b/docs/lending/guides/loan-writeback/deposit.md index c7c8e61c2..9609116e0 100644 --- a/docs/lending/guides/loan-writeback/deposit.md +++ b/docs/lending/guides/loan-writeback/deposit.md @@ -7,7 +7,7 @@ sidebar_label: "Deposit loan" import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -Once you receive the configuration information, you are ready to deposit funds into the borrower's bank account. This is known as *loan drawdown* general lending, and an *advance* in invoice finance. You will need to: +Once you receive the configuration information, you are ready to deposit funds into the borrower's bank account. This is known as *loan drawdown* in general lending, and an *advance* in invoice finance. You will need to: 1. [Create a transfer](/lending/guides/loan-writeback/deposit#create-transfer) from the lender's bank account to the borrower's bank account. @@ -28,7 +28,7 @@ Once you receive the configuration information, you are ready to deposit funds i To perform these operations, you will need the following properties: -- Lender's [`lendersBankAccount.id`](/lending-api#/AccountingBankAccount) +- Lender's [`lendersBankAccountId`](/lending-api#/AccountingBankAccount) - SMB's [`borrowersBankAccount.id`](/lending-api#/AccountingBankAccount) and `currency` - `depositDate` - the date the funding was deposited into the borrower's bank account - `depositAmount` - the funding amount or advance provided to the SMB @@ -39,7 +39,7 @@ To record the transfer of money from the lender's bank account to the borrower's 1. Use the [Get create transfer model](/lending-api#/operations/get-create-transfers-model) endpoint to determine the transfer request parameters. -2. Call the [Create transfer](/lending-api#/operations/create-transfer) endpoint to perform the transfer of money. Note that you are performing a transfer *from* `lendersBankAccount.id` *to* `borrowersBankAccount.id`. +2. Call the [Create transfer](/lending-api#/operations/create-transfer) endpoint to perform the transfer of money. Note that you are performing a transfer *from* `lendersBankAccountId` *to* `borrowersBankAccount.id`. @@ -50,7 +50,7 @@ codatLending.loanWriteback.transfers.create({ date: depositDate, from: { accountRef: { - id: lendersBankAccount.id, + id: lendersBankAccountId, }, amount: depositAmount, currency: borrowersBankAccount.currency, @@ -63,8 +63,8 @@ codatLending.loanWriteback.transfers.create({ currency: borrowersBankAccount.currency, }, }, - companyId: "8a210b68-6988-11ed-a1eb-0242ac120002", - connectionId: "2e9d2c44-f675-40ba-8049-353bfcb5e171", + companyId: companyId, + connectionId: connectionId, }).then((res: CreateTransferResponse) => { if (res.statusCode == 200) { // handle response @@ -81,7 +81,7 @@ transfers_create_request = operations.CreateTransferRequest( date_=deposit_date, from_=shared.TransferAccount( account_ref=shared.AccountRef( - id=lenders_bank_account.id, + id=lenders_bank_account_id, ), amount=Decimal(deposit_amount), currency=borrowers_bank_account.currency, @@ -94,8 +94,8 @@ transfers_create_request = operations.CreateTransferRequest( currency=borrowers_bank_account.currency, ), ), - company_id='8a210b68-6988-11ed-a1eb-0242ac120002', - connection_id='2e9d2c44-f675-40ba-8049-353bfcb5e171', + company_id=company_id, + connection_id=connection_id, ) transfers_create_response = codat_lending.loan_writeback.transfers.create(transfers_create_request) @@ -110,7 +110,7 @@ var transfersCreateResponse = await codatLending.LoanWriteback.Transfers.CreateA Date = depositDate, From = new TransferAccount() { AccountRef = new AccountRef() { - Id = lendersBankAccount.Id, + Id = lendersBankAccountId, }, Amount = depositAmount, Currency = borrowersBankAccount.currency, @@ -123,8 +123,8 @@ var transfersCreateResponse = await codatLending.LoanWriteback.Transfers.CreateA Currency = borrowersBankAccount.currency, }, }, - CompanyId = "8a210b68-6988-11ed-a1eb-0242ac120002", - ConnectionId = "2e9d2c44-f675-40ba-8049-353bfcb5e171", + CompanyId = companyId, + ConnectionId = connectionId, }); ``` @@ -138,7 +138,7 @@ transfersCreateResponse, err := codatLending.LoanWriteback.Transfers.Create(ctx, Date: lending.String(depositDate), From: &shared.TransferAccount{ AccountRef: &shared.AccountRef{ - ID: lending.String(lendersBankAccount.ID), + ID: lending.String(lendersBankAccountID), }, Amount: types.MustNewDecimalFromString(depositAmount), Currency: lending.String(borrowersBankAccount.currency), @@ -151,8 +151,8 @@ transfersCreateResponse, err := codatLending.LoanWriteback.Transfers.Create(ctx, Currency: lending.String(borrowersBankAccount.currency), }, }, - CompanyID: "8a210b68-6988-11ed-a1eb-0242ac120002", - ConnectionID: "2e9d2c44-f675-40ba-8049-353bfcb5e171", + CompanyID: companyID, + ConnectionID: connectionID, }) ``` @@ -170,7 +170,7 @@ POST https://api.codat.io/companies/{companyId}/connections/{connectionId}/push/ "date": depositDate, "from": { "accountRef": { - "id": lendersBankAccount.id, + "id": lendersBankAccountId, }, "account": depositAmount, "currency": borrowersBankAccount.currency, @@ -206,7 +206,7 @@ We provided example bank transaction creation payloads in the snippets below: ```javascript codatLending.loanWriteback.bankTransactions.create({ accountingCreateBankTransactions: { - accountId: lendersBankAccount.id, + accountId: lendersBankAccountId, transactions: [ { id: transactionId, // Unique identifier for this bank transaction @@ -217,8 +217,8 @@ codatLending.loanWriteback.bankTransactions.create({ ], }, accountId: lendersBankAccount.Id, - companyId: "8a210b68-6988-11ed-a1eb-0242ac120002", - connectionId: "2e9d2c44-f675-40ba-8049-353bfcb5e171", + companyId: companyId, + connectionId: connectionId, }).then((res: CreateBankTransactionsResponse) => { if (res.statusCode == 200) { // handle response @@ -232,7 +232,7 @@ if (res.statusCode == 200) { ```python bank_transactions_create_request = operations.CreateBankTransactionsRequest( accounting_create_bank_transactions=shared.AccountingCreateBankTransactions( - account_id=lenders_bank_account.id, + account_id=lenders_bank_account_id, transactions=[ shared.CreateBankAccountTransaction( id=transaction_id, # Unique identifier for this bank transaction @@ -243,8 +243,8 @@ bank_transactions_create_request = operations.CreateBankTransactionsRequest( ], ), account_id=lenders_bank_account.id, - company_id='8a210b68-6988-11ed-a1eb-0242ac120002', - connection_id='2e9d2c44-f675-40ba-8049-353bfcb5e171', + company_id=company_id, + connection_id=connection_id, ) bank_transactions_create_response = codat_lending.loan_writeback.bank_transactions.create(bank_transactions_create_request) @@ -256,7 +256,7 @@ bank_transactions_create_response = codat_lending.loan_writeback.bank_transactio ```csharp var bankTransactionsCreateResponse = await codatLending.LoanWriteback.BankTransactions.CreateAsync(new CreateBankTransactionsRequest() { AccountingCreateBankTransactions = new AccountingCreateBankTransactions() { - AccountId = lendersBankAccount.Id, + AccountId = lendersBankAccountId, Transactions = new List() { new CreateBankAccountTransaction() { Id = transactionId, // Unique identifier for this bank transaction @@ -267,8 +267,8 @@ var bankTransactionsCreateResponse = await codatLending.LoanWriteback.BankTransa }, }, AccountId = lendersBankAccount.Id, - CompanyId = "8a210b68-6988-11ed-a1eb-0242ac120002", - ConnectionId = "2e9d2c44-f675-40ba-8049-353bfcb5e171" + CompanyId = companyId, + ConnectionId = connectionId }); ``` @@ -290,8 +290,8 @@ bankTransactionsCreateRequest, err := codatLending.LoanWriteback.BankTransaction }, }, AccountID: lendersBankAccount.ID, - CompanyID: "8a210b68-6988-11ed-a1eb-0242ac120002", - ConnectionID: "2e9d2c44-f675-40ba-8049-353bfcb5e171", + CompanyID: companyID, + ConnectionID: connectionID, }) ``` @@ -306,7 +306,7 @@ POST https://api.codat.io/companies/{companyId}/connections/{connectionId}/push/ ```json { - "accountId": lendersBankAccount.id, + "accountId": lendersBankAccountId, "transactions": [{ "id": transactionId, // Unique identifier for this bank transaction "amount": -depositAmount, @@ -323,5 +323,4 @@ POST https://api.codat.io/companies/{companyId}/connections/{connectionId}/push/ ## Read next -* Record the repayment of a [general loan](/lending/guides/loan-writeback/record-general-loan). -* Record the repayment of an [invoice finance](/lending/guides/loan-writeback/record-invoice-finance) loan. \ No newline at end of file +* [Record the repayment of a loan](/lending/guides/loan-writeback/record-general-loan). \ No newline at end of file diff --git a/docs/lending/guides/loan-writeback/introduction.md b/docs/lending/guides/loan-writeback/introduction.md index 12e91a2d0..71cbb5e90 100644 --- a/docs/lending/guides/loan-writeback/introduction.md +++ b/docs/lending/guides/loan-writeback/introduction.md @@ -18,13 +18,21 @@ This guide takes you through the steps needed to implement and run the loan writ This solution covers the loan writeback procedure for both general lending, such as term loans, and selective invoice finance. +:::tip Save time with our SDK + +Deploy your loan writeback solution quicker by using our Lending SDK to integrate directly with our API. The loan writeback namespace includes all the methods you need to develop your loan writeback solution. + +Check out our SDKs for [TypeScript](https://github.com/codatio/client-sdk-typescript/tree/main/lending#loanwriteback), [Python](https://github.com/codatio/client-sdk-python/tree/main/lending#loan_writeback), [C#](https://github.com/codatio/client-sdk-csharp/tree/main/lending#loanwriteback), [Go](https://github.com/codatio/client-sdk-go/tree/main/lending#loanwriteback), and [Java](https://github.com/codatio/client-sdk-java/tree/main/lending#loanwriteback). + +::: + ### What is loan writeback? Loan writeback (also known as lending writeback) is the process of continuously updating an accounting software with information about a loan. It helps maintain an accurate position of the loan during the entire lending cycle by recording the loan liability, any interest, fees, or repayments, and facilitating the reconciliation of bank accounts. -:::tip Bank feeds for loan writeback +:::warning Bank feeds authorization -Loan writeback requires the lender to support the [bank feeds](/bank-feeds/overview) functionality so that the lender can record their own bank transactions associated with issuing the loan in their borrower's accounting software. +For some accounting software, you must obtain approval to integrate bank feeds prior to implementing loan writeback. ::: @@ -34,7 +42,9 @@ A bookkeeper can account for a loan in numerous ways in an accounting software. This results in loans being improperly recorded as revenue and repayments as operating costs. At the end of the reporting period, this can make it hard for the bookkeeper to close their books. -By implementing loan writeback functionality in your application, you can make sure loan bookeeping is done regularly, correctly, and quickly so that you always see an up-to-date state of the borrower's accounts. +By implementing loan writeback functionality in your application, you can make sure loan bookkeeping is done regularly, correctly, and quickly so that you always see an up-to-date state of the borrower's accounts. + +Critically, the loan writeback functionality helps lenders clearly identify loans in an SMB's accounting software. As a result, the lender sees a more accurate picture of the SMB's debt repayment history, which leads to improved underwriting. :::info Mandatory loan writeback @@ -52,7 +62,7 @@ The process of loan writeback involves recording loan withdrawals, repayments, a 3. **Record** payments owed to you, the lender, in your SMB's accounting software. -The first two steps are identical for the general lending and invoice finance scenarios. The process of recording repayments differs based on the lending option. +The process is identical for the general lending and invoice finance scenarios. ```mermaid sequenceDiagram @@ -102,22 +112,25 @@ In the example, you can also see that each bank feed transaction matches a bank The lender agrees to provide the SMB with an advance of £800 for a £1000 invoice with a £50 fee. The lender deposits £800 into the SMB's bank account and the SMB's customer pays for the invoice within the payment period. -In this instance, money moves from the lender's bank account into the borrower's bank account as fees, and the customer's invoice is paid directly into the lender's account. +When the SMB receives payment from the customer, the funds are transferred from the borrower's bank account into the lender's bank account, settling the loan and associated fees. The lender’s fee is then deducted from this payment. As a result, the lender's account transactions balance to zero, and the advance and the outstanding amount remain in the borrower's account. -![A GIF showing the money flow of an invoice finance writeback](/img/lending/loan-writeback-invoice-finance-example.gif) + + ## Prerequisites +* If you are implementing loan writeback for Xero, *Xero Bank Feeds API* needs to be enabled for your registered app. Xero usually does this during the certification process for lenders' apps so that you can test your solution before completing the certification. + * Check that you have [created a Codat company](/configure/portal/companies#add-a-new-company) that represents your SMB customer and linked it to an accounting software. If you are already using Codat for lending, it's likely you have previously created some companies. You should also create and connect a test company to use while building your solution. -* Familiarize yourself with Codat's approach of asynchronously [creating and updating data](/using-the-api/push), which can be summarized as follows: +* Familiarize yourself with Codat's asynchronous approach to [writing data](/using-the-api/push), which leverages [webhooks](/using-the-api/webhooks/overview). This process can be summarized as follows: ```mermaid sequenceDiagram @@ -127,18 +140,14 @@ As a result, the lender's account transactions balance to zero, and the advance backend ->> codat: Create record (data type) codat -->> backend: Write operation key - codat -->> backend: Write operation status webhook + codat -->> backend: {dataType}.write.{successful|unsuccessful} webhook alt Status is successful backend ->> codat: Get write operation - codat -->> backend: write operation + codat -->> backend: Write operation end ``` -* If you are implementing loan writeback for Xero, *Xero Bank Feeds API* needs to be enabled for your registered app. Xero usually does this during the certification process for lenders' apps so that you can test your solution before completing the certification. - -* As a lender, use Codat's [Bank Feeds API](/bank-feeds/overview) to represent your bank account in Codat's domain. Keep hold of the [source bank account](/bank-feeds-api#/operations/create-source-account) `id` as you will use it when recording deposits and repayments. - --- ## Read next diff --git a/docs/lending/guides/loan-writeback/record-general-loan.md b/docs/lending/guides/loan-writeback/record-general-loan.md index 732a110fa..c8923f0f1 100644 --- a/docs/lending/guides/loan-writeback/record-general-loan.md +++ b/docs/lending/guides/loan-writeback/record-general-loan.md @@ -1,15 +1,19 @@ --- -title: "Record general loan repayments" -description: "Record the repayment of money owed to the lender for a general loan in the SMB's accounting software" -sidebar_label: "Record: general loans" +title: "Record loan repayments" +description: "Record the repayment of money owed to the lender for a loan in the SMB's accounting software" +sidebar_label: "Record repayments" --- import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -Based on the loan's terms and conditions, the borrower will periodically repay the lender the loan amount and any associated fees. +The loan writeback process is the same for general lending and invoice finance. The key distinction lies in the repayment method: general lending usually involves recurring payments, while invoice finance is repaid when the SMB’s customer pays the invoice. -To reflect that programmatically, perform these steps every time a repayment is made: +On this page, we focus on general lending and provide additional details on automating the process for invoice finance providers. + +## Record repayment + +To reflect loan repayments programmatically, perform these steps every time a repayment is made: 1. [Create a transfer](/lending/guides/loan-writeback/record-general-loan#create-transfer) from the borrower's bank account to the lender's for each repayment. @@ -21,6 +25,12 @@ For example, if the borrower took out a loan of £1000 with a loan charge of 20% This means you need to create a transfer of £320 to represent the payment, a direct cost of £80 to record the fees, and a bank transaction of £400 to reduce the liability to the lender. +:::info Repay on your terms + +Our example shows how to record loan repayments with monthly payments covering both drawdown and fees. To separate repayments from fee or interest payments, include a transfer from the borrower’s account to the lender’s account that equals the amount of fees or interest. Then, create the associated direct cost to register the fees and/or interest. + +::: + ```mermaid sequenceDiagram participant application as Your application @@ -41,7 +51,7 @@ sequenceDiagram ``` To perform these operations, you will need the following properties: -- Lender's [`supplier.id`](/lending-api#/schemas/AccountingSupplier) and [`lendersBankAccount.id`](/lending-api#/AccountingBankAccount) +- Lender's [`supplier.id`](/lending-api#/schemas/AccountingSupplier) and [`lendersBankAccountId`](/lending-api#/AccountingBankAccount) - SMB's [`expenseAccount.id`](/lending-api#/schemas/AccountingAccount), [`borrowersBankAccount.id`](/lending-api#/AccountingBankAccount), and `currency` - `repaymentDate` - the date of the repayment - `repaymentAmount` - the amount repaying the loan amount @@ -50,7 +60,7 @@ To perform these operations, you will need the following properties: ### Create transfer -Use the [Create transfer](/lending-api#/operations/create-transfer) endpoint again, this time to record the loan repayment amount. Note that you are performing a transfer *from* `borrowersBankAccount.id` *to* `lendersBankAccount.id`. +Use the [Create transfer](/lending-api#/operations/create-transfer) endpoint again, this time to record the total repayment amount. Note that you are performing a transfer *from* `borrowersBankAccount.id` *to* `lendersBankAccountId`. @@ -63,19 +73,19 @@ codatLending.loanWriteback.transfers.create({ accountRef: { id: borrowersBankAccount.id, }, - amount: repaymentAmount, + amount: totalRepaymentAmount, currency: borrowersBankAccount.currency, }, to: { accountRef: { - id: lendersBankAccount.id, + id: lendersBankAccountId, }, - amount: repaymentAmount, + amount: totalRepaymentAmount, currency: borrowersBankAccount.currency, }, }, - companyId: "8a210b68-6988-11ed-a1eb-0242ac120002", - connectionId: "2e9d2c44-f675-40ba-8049-353bfcb5e171", + companyId: companyId, + connectionId: connectionId, }).then((res: CreateTransferResponse) => { if (res.statusCode == 200) { // handle response @@ -94,19 +104,19 @@ transfers_create_request = operations.CreateTransferRequest( account_ref=shared.AccountRef( id=borrowers_bank_account.id, ), - amount=Decimal(repayment_amount), + amount=Decimal(total_repayment_amount), currency=borrowers_bank_account.currency, ), to=shared.TransferAccount( account_ref=shared.AccountRef( - id=lenders_bank_account.id, + id=lenders_bank_account_id, ), - amount=Decimal(repayment_amount), + amount=Decimal(total_repayment_amount), currency=borrowers_bank_account.currency, ), ), - company_id='8a210b68-6988-11ed-a1eb-0242ac120002', - connection_id='2e9d2c44-f675-40ba-8049-353bfcb5e171', + company_id=company_id, + connection_id=connection_id, ) transfers_create_response = codat_lending.loan_writeback.transfers.create(transfers_create_request) @@ -123,19 +133,19 @@ var transfersCreateResponse = await codatLending.LoanWriteback.Transfers.CreateA AccountRef = new AccountRef() { Id = borrowersBankAccount.Id, }, - Amount = repaymentAmount, + Amount = totalRepaymentAmount, Currency = borrowersBankAccount.Currency, }, To = new TransferAccount() { AccountRef = new AccountRef() { - Id = lendersBankAccount.Id, + Id = lendersBankAccountId, }, - Amount = repaymentAmount, + Amount = totalRepaymentAmount, Currency = borrowersBankAccount.Currency, }, }, - CompanyId = "8a210b68-6988-11ed-a1eb-0242ac120002", - ConnectionId = "2e9d2c44-f675-40ba-8049-353bfcb5e171", + CompanyId = companyId, + ConnectionId = connectionId, }); ``` @@ -149,25 +159,58 @@ transfersCreateResponse, err := codatLending.LoanWriteback.Transfers.Create(ctx, Date: lending.String(repaymentDate), From: &shared.TransferAccount{ AccountRef: &shared.AccountRef{ - ID: lending.String(borrowersBankAccountID), + ID: lending.String(borrowersBankAccount.ID), }, - Amount: types.MustNewDecimalFromString(repaymentAmount), + Amount: types.MustNewDecimalFromString(totalRepaymentAmount), Currency: lending.String(borrowersBankAccount.Currency), }, To: &shared.TransferAccount{ AccountRef: &shared.AccountRef{ - ID: lending.String(lendersBankAccount.ID), + ID: lending.String(lendersBankAccountID), }, - Amount: types.MustNewDecimalFromString(repaymentAmount), + Amount: types.MustNewDecimalFromString(totalRepaymentAmount), Currency: lending.String(borrowersBankAccount.Currency), }, }, - CompanyID: "8a210b68-6988-11ed-a1eb-0242ac120002", - ConnectionID: "2e9d2c44-f675-40ba-8049-353bfcb5e171", + CompanyID: companyID, + ConnectionID: connectionID, }) ``` + + +```java +CreateTransferRequest req = CreateTransferRequest.builder() + .companyId(companyId) + .connectionId(connectionId) + .accountingTransfer(AccountingTransfer.builder() + .date(repaymentDate) + .from(TransferAccount.builder() + .accountRef(AccountRef.builder() + .id(borrowersBankAccount.id) + .build() + ) + .amount(totalRepaymentAmount) + .currency(borrowersBankAccount.currency) + .build()) + .to(TransferAccount.builder() + .accountRef(AccountRef.builder() + .id(lendersBankAccountId) + .build() + ) + .amount(totalRepaymentAmount) + .currency(borrowersBankAccount.currency) + .build()) + .build()) + .build(); + +CreateTransferResponse res = codatLending.loanWriteback().transfers().create() + .request(req) + .call(); +``` + + ```http @@ -183,14 +226,14 @@ POST https://api.codat.io/companies/{companyId}/connections/{connectionId}/push/ "accountRef": { "id": borrowersBankAccount.id, }, - "account": repaymentAmount, + "account": totalRepaymentAmount, "currency": borrowersBankAccount.currency, }, "to": { "accountRef": { - "id": lendersBankAccount.id, + "id": lendersBankAccountId, }, - "account": repaymentAmount, + "account": totalRepaymentAmount, "currency": borrowersBankAccount.currency, } } @@ -234,7 +277,7 @@ codatLending.loanWriteback.directCosts.create({ }, payment: { accountRef: { - id: borrowersBankAccount.id, + id: lendersBankAccountId, }, }, }, @@ -242,8 +285,8 @@ codatLending.loanWriteback.directCosts.create({ taxAmount: 0.0, totalAmount: interestAndFeesAmount, }, - companyId: "8a210b68-6988-11ed-a1eb-0242ac120002", - connectionId: "2e9d2c44-f675-40ba-8049-353bfcb5e171", + companyId: companyId, + connectionId: connectionId, }).then((res: CreateDirectCostResponse) => { if (res.statusCode == 200) { // handle response @@ -281,7 +324,7 @@ direct_costs_create_request = operations.CreateDirectCostRequest( ), payment=shared.PaymentAllocationPayment( account_ref=shared.AccountRef( - id=borrowers_bank_account.id, + id=lenders_bank_account_id, ), ), ), @@ -289,8 +332,8 @@ direct_costs_create_request = operations.CreateDirectCostRequest( tax_amount=Decimal('0'), total_amount=Decimal(interest_and_fees_amount), ), - company_id='8a210b68-6988-11ed-a1eb-0242ac120002', - connection_id='2e9d2c44-f675-40ba-8049-353bfcb5e171', + company_id=company_id, + connection_id=connection_id, ) direct_costs_create_response = codat_lending.loan_writeback.direct_costs.create(direct_costs_create_request) @@ -326,7 +369,7 @@ var redirectCostsCreateResponse = await codatLending.LoanWriteback.DirectCosts.C }, Payment = new PaymentAllocationPayment() { AccountRef = new AccountRef() { - Id = borrowersBankAccount.Id, + Id = lendersBankAccountId, }, }, }, @@ -334,8 +377,8 @@ var redirectCostsCreateResponse = await codatLending.LoanWriteback.DirectCosts.C TaxAmount = 0M, TotalAmount = interestAndFeesAmount, }, - CompanyId = "8a210b68-6988-11ed-a1eb-0242ac120002", - ConnectionId = "2e9d2c44-f675-40ba-8049-353bfcb5e171", + CompanyId = companyId, + ConnectionId = connectionId, }); ``` @@ -344,7 +387,7 @@ var redirectCostsCreateResponse = await codatLending.LoanWriteback.DirectCosts.C ```go ctx := context.Background() -res, err := s.LoanWriteback.DirectCosts.Create(ctx, operations.CreateDirectCostRequest{ +res, err := codatLending.LoanWriteback.DirectCosts.Create(ctx, operations.CreateDirectCostRequest{ AccountingDirectCost: &shared.AccountingDirectCost{ ContactRef: &shared.ContactRef{ DataType: lending.String("suppliers"), @@ -370,7 +413,7 @@ res, err := s.LoanWriteback.DirectCosts.Create(ctx, operations.CreateDirectCostR }, Payment: shared.PaymentAllocationPayment{ AccountRef: &shared.AccountRef{ - ID: lending.String(borrowersBankAccount.ID), + ID: lending.String(lendersBankAccountID), }, }, }, @@ -378,12 +421,67 @@ res, err := s.LoanWriteback.DirectCosts.Create(ctx, operations.CreateDirectCostR TaxAmount: types.MustNewDecimalFromString("0"), TotalAmount: types.MustNewDecimalFromString(interestAndFeesAmount), }, - CompanyID: "8a210b68-6988-11ed-a1eb-0242ac120002", - ConnectionID: "2e9d2c44-f675-40ba-8049-353bfcb5e171", + CompanyID: companyID, + ConnectionID: connectionID, }) ``` + + +```java +CreateDirectCostRequest req = CreateDirectCostRequest.builder() + .companyId(companyId) + .connectionId(connectionId) + .directCostPrototype(DirectCostPrototype.builder() + contactRef(ContactRef.builder() + .dataType("suppliers") + .id(supplier.Id) + .build() + ) + .currency(borrowersBankAccount.currency) + .issueDate(repaymentDate) + .lineItems(List.of( + DirectCostLineItem.builder() + .accountRef(AccountRef.builder() + .id(expenseAccount.Id) + .build() + ) + .description("Fees and/or interest") + .quantity(new BigDecimal("1")) + + .taxAmount(new BigDecimal("0")) + .unitAmount(new BigDecimal(interestAndFeesAmount)) + .build() + ) + ) + .paymentAllocations(List.of( + AccountingPaymentAllocation.builder() + .allocation(Allocation.builder() + .totalAmount(new BigDecimal(interestAndFeesAmount)) + .build() + ) + .payment(PaymentAllocationPayment.builder() + .accountRef(AccountRef.builder() + .id(expenseAccount.Id) + .build() + ) + .build() + ) + .build() + ) + ) + .taxAmount(new BigDecimal("0")) + .totalAmount(new BigDecimal(interestAndFeesAmount)) + .build()) + .build(); + +CreateDirectCostResponse res = codatLending.loanWriteback().directCosts().create() + .request(req) + .call(); +``` + + ```http @@ -405,7 +503,7 @@ POST https://api.codat.io/companies/{companyId}/connections/{connectionId}/push/ "paymentAllocations": [{ "payment": { "accountRef": { - "id": borrowersBankAccount.id + "id": lendersBankAccountId } }, "allocation": { @@ -447,9 +545,9 @@ codatLending.loanWriteback.bankTransactions.create({ }, ], }, - accountId: lendersBankAccount.Id, - companyId: "8a210b68-6988-11ed-a1eb-0242ac120002", - connectionId: "2e9d2c44-f675-40ba-8049-353bfcb5e171", + accountId: lendersBankAccountId, + companyId: companyId, + connectionId: connectionId, }).then((res: CreateBankTransactionsResponse) => { if (res.statusCode == 200) { // handle response @@ -463,7 +561,7 @@ if (res.statusCode == 200) { ```python bank_transactions_create_request = operations.CreateBankTransactionsRequest( accounting_create_bank_transactions=shared.AccountingCreateBankTransactions( - account_id=lenders_bank_account.id, + account_id=lenders_bank_account_id, transactions=[ shared.CreateBankAccountTransaction( id=transaction_id, # Unique identifier for this bank transaction @@ -474,8 +572,8 @@ bank_transactions_create_request = operations.CreateBankTransactionsRequest( ], ), account_id=lenders_bank_account.id, - company_id='8a210b68-6988-11ed-a1eb-0242ac120002', - connection_id='2e9d2c44-f675-40ba-8049-353bfcb5e171', + company_id=company_id, + connection_id=connection_id, ) bank_transactions_create_response = codat_lending.loan_writeback.bank_transactions.create(bank_transactions_create_request) @@ -487,7 +585,7 @@ bank_transactions_create_response = codat_lending.loan_writeback.bank_transactio ```csharp var bankTransactionsCreateResponse = await codatLending.LoanWriteback.BankTransactions.CreateAsync(new CreateBankTransactionsRequest() { AccountingCreateBankTransactions = new AccountingCreateBankTransactions() { - AccountId = lendersBankAccount.Id, + AccountId = lendersBankAccountId, Transactions = new List() { new CreateBankAccountTransaction() { Id = transactionId, // Unique identifier for this bank transaction @@ -498,8 +596,8 @@ var bankTransactionsCreateResponse = await codatLending.LoanWriteback.BankTransa }, }, AccountId = lendersBankAccount.Id, - CompanyId = "8a210b68-6988-11ed-a1eb-0242ac120002", - ConnectionId = "2e9d2c44-f675-40ba-8049-353bfcb5e171" + CompanyId = companyId, + ConnectionId = connectionId }); ``` @@ -510,7 +608,7 @@ var bankTransactionsCreateResponse = await codatLending.LoanWriteback.BankTransa ctx := context.Background() bankTransactionsCreateRequest, err := codatLending.LoanWriteback.BankTransactions.Create(ctx, operations.CreateBankTransactionsRequest{ AccountingCreateBankTransactions: &shared.AccountingCreateBankTransactions{ - AccountID: lending.String(lendersBankAccount.ID), + AccountID: lending.String(lendersBankAccountID), Transactions: []shared.CreateBankAccountTransaction{ shared.CreateBankAccountTransaction{ ID: lending.String(transactionID), // Unique identifier for this bank transaction @@ -520,10 +618,36 @@ bankTransactionsCreateRequest, err := codatLending.LoanWriteback.BankTransaction }, }, }, - AccountID: lendersBankAccount.ID, - CompanyID: "8a210b68-6988-11ed-a1eb-0242ac120002", - ConnectionID: "2e9d2c44-f675-40ba-8049-353bfcb5e171", - }) + AccountID: lendersBankAccountID, + CompanyID: companyID, + ConnectionID: connectionID, +}) +``` + + + + +```java +CreateBankTransactionsRequest req = CreateBankTransactionsRequest.builder() + .companyId(companyId) + .connectionId(connectionId) + .accountId(lendersBankAccountId) + .accountingCreateBankTransactions(AccountingCreateBankTransactions.builder() + .accountId(lendersBankAccountId) + .transactions(List.of( + CreateBankAccountTransaction.builder() + .id(transactionID) // Unique identifier for this bank transaction + .amount(new BigDecimal(totalRepaymentAmount)) + .date(repaymentDate) + .description(description) // Include a reference to the direct cost, the loan and you, the lender + .build())) + .build()) + .build(); + +CreateBankTransactionsResponse res = codatLending.loanWriteback().bankTransactions().create() + .request(req) + .call(); + ``` @@ -537,7 +661,7 @@ POST https://api.codat.io/companies/{companyId}/connections/{connectionId}/push/ ```json { - "accountId": lendersBankAccount.Id, + "accountId": lendersBankAccountId, "transactions": [{ "id": transactionId, // Unique identifier for this bank transaction "amount": totalRepaymentAmount, @@ -552,6 +676,12 @@ POST https://api.codat.io/companies/{companyId}/connections/{connectionId}/push/ At the end of this 3-stage process, your borrower will have the loan writeback reflected correctly in their accounting software. This saves them time on reconciliation and makes sure they (and you!) have clarity on the state of the loan. +## Invoice finance repayments + +Some accounting software providers offer webhook notifications that alert you about changes to invoices in the SMB’s accounts. By subscribing to these notifications, you can automatically trigger repayments once the customer pays the SMB. + +To enhance your repayment automation, check out the supported webhooks from [Xero](https://developer.xero.com/documentation/guides/webhooks/overview/) and [Intuit](https://developer.intuit.com/app/developer/qbo/docs/develop/webhooks). + :::tip Recap In this guide, you have learned: * What is loan writeback and what it's used for. diff --git a/docs/lending/guides/loan-writeback/record-invoice-finance.md b/docs/lending/guides/loan-writeback/record-invoice-finance.md deleted file mode 100644 index 1c8dfc248..000000000 --- a/docs/lending/guides/loan-writeback/record-invoice-finance.md +++ /dev/null @@ -1,827 +0,0 @@ ---- -title: "Record invoice finance repayments" -description: "Record the repayment of money owed to the lender for an invoice financing loan in the SMB's accounting software" -sidebar_label: "Record: invoice finance" ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; -import WritebackMapping from "@components/Prototypes/WritebackMapping"; - -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 software. - -To reflect that programmatically, perform these steps: - -1. [Create a transfer](/lending/guides/loan-writeback/record-invoice-finance#create-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](/lending/guides/loan-writeback/record-invoice-finance#create-direct-cost) against the lender's bank account. - -3. To update the invoice as paid, [create a payment](/lending/guides/loan-writeback/record-invoice-finance#create-payment) in the lender's bank account. - -4. [Create bank feed transactions](/lending/guides/loan-writeback/record-invoice-finance#create-bank-feed-transactions) to represent the transfer, direct cost and invoice payment in the lender's bank account. - -```mermaid -sequenceDiagram - participant backend as Your application - participant codat as Codat - - backend ->> codat: Create transfer (lender -> bank account) - codat -->> backend: transfer - - backend ->> codat: Create direct cost - codat -->> backend: direct cost - - backend ->> codat: Create payment (on invoice) - codat -->> backend: payment - - backend ->> codat: Create bank feed transactions (transfer, direct cost and invoice payment amounts) - codat -->> backend: bank feed transactions -``` - -To perform these operations, you will need the following properties: - -- Lender's [`supplier.id`](/lending-api#/schemas/AccountingSupplier) and [`lendersBankAccount.id`](/lending-api#/AccountingBankAccount) -- SMB's [`expenseAccount.id`](/lending-api#/schemas/AccountingAccount), [`borrowersBankAccount.id`](/lending-api#/AccountingBankAccount), and `currency` -- Interest and fee amounts -- [Invoice](/lending-api#/AccountingInvoice) properties of `id`, `totalAmount, and `customerRef.id` - -### Create transfer - -Once the SMB's customer pays the invoice, use the [Create transfer](/lending-api#/operations/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. - - - - -```javascript -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 - } -}); -``` - - - - -```python -transfers_create_request = operations.CreateTransferRequest( - accounting_transfer=shared.AccountingTransfer( - date_=outstanding_amount_transfer_date, - from_=shared.TransferAccount( - account_ref=shared.AccountRef( - id=lenders_bank_account.id, - ), - amount=Decimal(outstanding_amount), - currency=borrowers_bank_account.currency, - ), - to=shared.TransferAccount( - account_ref=shared.AccountRef( - id=borrowers_bank_account.id, - ), - amount=Decimal(outstanding_amount), - currency=borrowers_bank_account.currency, - ), - ), - company_id='8a210b68-6988-11ed-a1eb-0242ac120002', - connection_id='2e9d2c44-f675-40ba-8049-353bfcb5e171', -) - -transfers_create_response = codat_lending.loan_writeback.transfers.create(transfers_create_request) -``` - - - - -```csharp -var transfersCreateResponse = await codatLending.LoanWriteback.Transfers.CreateAsync(new CreateTransferRequest() { - AccountingTransfer = new AccountingTransfer() { - Date = outstandingAmountTransferDate, - From = new TransferAccount() { - AccountRef = new AccountRef() { - Id = lendersBankAccount.Id, - }, - Amount = outstandingAmount, - Currency = borrowersBankAccount.Currency, - }, - To = new TransferAccount() { - AccountRef = new AccountRef() { - Id = borrowersBankAccount.Id, - }, - Amount = outstandingAmount, - Currency = borrowersBankAccount.Currency, - }, - }, - CompanyId = "8a210b68-6988-11ed-a1eb-0242ac120002", - ConnectionId = "2e9d2c44-f675-40ba-8049-353bfcb5e171", -}); -``` - - - - -```go -ctx := context.Background() -transfersCreateResponse, err := codatLending.LoanWriteback.Transfers.Create(ctx, operations.CreateTransferRequest{ - AccountingTransfer: &shared.AccountingTransfer{ - Date: lending.String(outstandingAmountTransferDate), - From: &shared.TransferAccount{ - AccountRef: &shared.AccountRef{ - ID: lending.String(lendersBankAccount.ID), - }, - Amount: types.MustNewDecimalFromString(outstandingAmount), - Currency: lending.String(borrowersBankAccount.Currency), - }, - To: &shared.TransferAccount{ - AccountRef: &shared.AccountRef{ - ID: lending.String(borrowersBankAccount.ID), - }, - Amount: types.MustNewDecimalFromString(outstandingAmount), - Currency: lending.String(borrowersBankAccount.Currency), - }, - }, - CompanyID: "8a210b68-6988-11ed-a1eb-0242ac120002", - ConnectionID: "2e9d2c44-f675-40ba-8049-353bfcb5e171", -}) -``` - - - - -```http -POST https://api.codat.io/companies/{companyId}/connections/{connectionId}/push/transfers -``` - -#### Request body - -```json -{ - "date": outstandingAmountTransferDate, - "from": { - "accountRef": { - "id": lendersBankAccount.id, - }, - "account": outstandingAmount, - "currency": borrowersBankAccount.currency, - }, - "to": { - "accountRef": { - "id": borrowersBankAccount.id, - }, - "account": outstandingAmount, - "currency": borrowersBankAccount.currency, - } -} -``` - - - - - -### Create direct cost - -Check the [Get create direct cost model](/lending-api#/operations/get-create-directCosts-model), then use the [Create direct cost](/lending-api#/operations/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. - - - - -```javascript -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 - } -}); -``` - - - - -```python -direct_costs_create_request = operations.CreateDirectCostRequest( - accounting_direct_cost=shared.AccountingDirectCost( - contact_ref=shared.ContactRef( - data_type='suppliers', - id=supplier.id, - ), - currency=borrowers_bank_account.currency, - issue_date=direct_cost_issue_date, - line_items=[ - shared.DirectCostLineItem( - account_ref=shared.AccountRef( - id=expense_account.id, - ), - description='Fees and/or interest', - quantity=Decimal('1'), - tax_amount=Decimal('0'), - unit_amount=Decimal(fee_and_interest_amount), - ), - ], - payment_allocations=[ - shared.AccountingPaymentAllocation( - allocation=shared.AccountingPaymentAllocationAllocation( - total_amount=Decimal(fee_and_interest_amount), - ), - payment=shared.PaymentAllocationPayment( - account_ref=shared.AccountRef( - id=lenders_bank_account.id, - ), - ), - ), - ], - tax_amount=Decimal('0'), - total_amount=Decimal(fee_and_interest_amount), - ), - company_id='8a210b68-6988-11ed-a1eb-0242ac120002', - connection_id='2e9d2c44-f675-40ba-8049-353bfcb5e171', -) - -direct_costs_create_response = codat_lending.loan_writeback.direct_costs.create(direct_costs_create_request) -``` - - - - -```csharp -var redirectCostsCreateResponse = await codatLending.LoanWriteback.DirectCosts.CreateAsync(new CreateDirectCostRequest() { - AccountingDirectCost = new AccountingDirectCost() { - ContactRef = new ContactRef() { - DataType = "suppliers", - Id = supplier.id, - }, - Currency = borrowersBankAccount.Currency, - IssueDate = feeAndInterestIssueDate, - LineItems = new List() { - new DirectCostLineItem() { - AccountRef = new AccountRef() { - Id = expenseAccount.Id, - }, - Description = "Fees and/or interest", - Quantity = 1M, - TaxAmount = 0M, - UnitAmount = feeAndInterestAmount, - }, - }, - PaymentAllocations = new List() { - new AccountingPaymentAllocation() { - Allocation = new AccountingPaymentAllocationAllocation() { - TotalAmount = feeAndInterestAmount, - }, - Payment = new PaymentAllocationPayment() { - AccountRef = new AccountRef() { - Id = lendersBankAccount.Id, - }, - }, - }, - }, - TaxAmount = 0M, - TotalAmount = feeAndInterestAmount, - }, - CompanyId = "8a210b68-6988-11ed-a1eb-0242ac120002", - ConnectionId = "2e9d2c44-f675-40ba-8049-353bfcb5e171", -}); -``` - - - - -```go -ctx := context.Background() -res, err := s.LoanWriteback.DirectCosts.Create(ctx, operations.CreateDirectCostRequest{ - AccountingDirectCost: &shared.AccountingDirectCost{ - ContactRef: &shared.ContactRef{ - DataType: lending.String("suppliers"), - ID: supplier.ID, - }, - Currency: borrowersBankAccount.Currency, - IssueDate: feeAndInterestIssueDate, - LineItems: []shared.DirectCostLineItem{ - shared.DirectCostLineItem{ - AccountRef: &shared.AccountRef{ - ID: lending.String(expenseAccount.ID), - }, - Description: lending.String("Fees and/or interest"), - Quantity: types.MustNewDecimalFromString("1"), - TaxAmount: types.MustNewDecimalFromString("0"), - UnitAmount: types.MustNewDecimalFromString(feeAndInterestAmount), - }, - }, - PaymentAllocations: []shared.AccountingPaymentAllocation{ - shared.AccountingPaymentAllocation{ - Allocation: shared.AccountingPaymentAllocationAllocation{ - TotalAmount: types.MustNewDecimalFromString(feeAndInterestAmount), - }, - Payment: shared.PaymentAllocationPayment{ - AccountRef: &shared.AccountRef{ - ID: lending.String(lendersBankAccount.ID), - }, - }, - }, - }, - TaxAmount: types.MustNewDecimalFromString("0"), - TotalAmount: types.MustNewDecimalFromString(feeAndInterestAmount), - }, - CompanyID: "8a210b68-6988-11ed-a1eb-0242ac120002", - ConnectionID: "2e9d2c44-f675-40ba-8049-353bfcb5e171", -}) -``` - - - - -```http -POST https://api.codat.io/companies/{companyId}/connections/{connectionId}/push/directCosts -``` - -#### Request body - -```json -{ - "issueDate": feeAndInterestIssueDate, - "currency": borrowersBankAccount.currency, - "taxAmount": 0.0, - "totalAmount": feeAndInterestAmount, - "contactRef": { - "id": supplier.id, - "dataType": "suppliers" - }, - "paymentAllocations": [{ - "payment": { - "accountRef": { - "id": lendersBankAccount.id - } - }, - "allocation": { - "totalAmount": feeAndInterestAmount - } - }], - "lineItems": [{ - "description": "Fees and/or interest", - "quantity": 1, - "unitAmount": feeAndInterestAmount, - "taxAmount": 0, - "accountRef": { - "id": expenseAccount.id - } - }] -} -``` - - - - -### Create payment - -Next, use the [Create payment](/lending-api#/operations/create-payment) endpoint to acknowledge payment has been received for the invoice. Store the `invoicePaymentDate` for use later on in your application. - - - - -```javascript -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 - } -}); -``` - - - - -```python -payment_create_request = operations.CreatePaymentRequest( - accounting_payment=shared.AccountingPayment( - account_ref=shared.AccountRef( - id=lenders_bank_account.id, - ), - currency=borrowers_bank_account.currency, - customer_ref=shared.AccountingCustomerRef( - id=invoice.customer_ref.id, - ), - date_=invoice_payment_date, - lines=[ - shared.PaymentLine( - allocated_on_date=invoice_payment_date, - amount=Decimal(f'{invoice.total_amount}'), # The sum of the link amounts plus the line amount must equal zero - links=[ - shared.PaymentLineLink( - amount=Decimal(f'-{invoice.total_amount}'), # Note the negative sign is here - currency_rate=Decimal('1'), - id=invoice.id, - type=shared.PaymentLinkType.INVOICE, - ), - ], - ), - ], - total_amount=Decimal(f'{invoice.total_amount}'), - ), - company_id='8a210b68-6988-11ed-a1eb-0242ac120002', - connection_id='2e9d2c44-f675-40ba-8049-353bfcb5e171', -) - -payment_create_response = codat_lending.loan_writeback.payments.create(payment_create_request) -``` - - - - -```csharp -var res = await codatLending.LoanWriteback.Payments.CreateAsync(new CreatePaymentRequest() { - AccountingPayment = new AccountingPayment() { - AccountRef = new AccountRef() { - Id = lendersBankAccount.Id, - }, - Currency = borrowersBankAccount.Currency, - CustomerRef = new AccountingCustomerRef() { - Id = invoice.CustomerRef.Id, - }, - Date = invoicePaymentDate, - Lines = new List() { - new PaymentLine() { - AllocatedOnDate = invoicePaymentDate, - Amount = invoice.TotalAmount, // The sum of the link amounts plus the line amount must equal zero - Links = new List() { - new PaymentLineLink() { - Amount = -invoice.TotalAmount, // Note the negative sign is here - CurrencyRate = 1M, - Id = invoice.Id, - Type = PaymentLinkType.Invoice, - }, - }, - }, - }, - TotalAmount = invoice.TotalAmount, - }, - CompanyId = "8a210b68-6988-11ed-a1eb-0242ac120002", - ConnectionId = "2e9d2c44-f675-40ba-8049-353bfcb5e171", -}); -``` - - - - -```go -ctx := context.Background() -res, err := codatLending.LoanWriteback.Payments.Create(ctx, operations.CreatePaymentRequest{ - AccountingPayment: &shared.AccountingPayment{ - AccountRef: &shared.AccountRef{ - ID: lending.String(lendersBankAccount.ID), - }, - Currency: lending.String(borrowersBankAccount.Currency), - CustomerRef: &shared.AccountingCustomerRef{ - ID: invoice.CustomerRef.ID, - }, - Date: invoicePaymentDate, - Lines: []shared.PaymentLine{ - shared.PaymentLine{ - AllocatedOnDate: lending.String(invoicePaymentDate), - Amount: invoice.TotalAmount,// The sum of the link amounts plus the line amount must equal zero - Links: []shared.PaymentLineLink{ - shared.PaymentLineLink{ - Amount: -invoice.TotalAmount, // Note the negative sign is here - CurrencyRate: types.MustNewDecimalFromString("1"), - ID: lending.String(invoice.ID), - Type: shared.PaymentLinkTypeInvoice, - }, - }, - }, - }, - TotalAmount: types.MustNewDecimalFromString(invoice.TotalAmount), - }, - CompanyID: "8a210b68-6988-11ed-a1eb-0242ac120002", - ConnectionID: "2e9d2c44-f675-40ba-8049-353bfcb5e171", -}) -``` - - - - -```http -POST https://api.codat.io/companies/{companyId}/connections/{connectionId}/push/payments -``` - -#### Request body - -```json -{ - "customerRef": { - "id": invoice.customerRef.id, - }, - "accountRef": { - "id": lendersBankAccount.id, - }, - "totalAmount": invoice.totalAmount, - "currency": borrowersBankAccount.currency, - "currencyRate": 1, - "date": invoicePaymentDate, - "lines": [ - { - "amount": invoice.totalAmount, // The sum of amount and line amounts must equal zero - "links": [ - { - "type": "Invoice", - "id": invoice.id, - "amount": -invoice.totalAmount, // Note the negative sign is here - "currencyRate": 1 - } - ], - "allocatedOnDate": invoicePaymentDate - } - ], -} -``` - - - - -### Create bank feed transactions - -Finally, use the [Create bank account transactions](/lending-api#/operations/create-bank-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. - - - - -```javascript -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 -} -}); -``` - - - - -```python -bank_transactions_create_request = operations.CreateBankTransactionsRequest( - accounting_create_bank_transactions=shared.AccountingCreateBankTransactions( - account_id=lenders_bank_account.id, # Lender's virtual bank account ID you would have stored from the configuration step - transactions=[ - shared.CreateBankAccountTransaction( - id=transactionId, # Unique identifier for this bank transaction - amount=Decimal(fee_and_interest_amount), - date=fee_and_interest_issue_date, - description=description, # Include a reference to supplier and direct cost - ), - shared.CreateBankAccountTransaction( - id=transactionId, # Unique identifier for this bank transaction - amount=Decimal(outstanding_amount), - date=outstanding_amount_transfer_date, - description=description, # Include a reference to transfer - ), - shared.CreateBankAccountTransaction( - id=transactionId, # Unique identifier for this bank transaction - amount=Decimal(invoice_amount), - date=invoice_payment_date, - description=description, # Include a reference to the customer and invoice number/ID - ), - ], - ), - account_id=lenders_bank_account.id, - company_id='8a210b68-6988-11ed-a1eb-0242ac120002', - connection_id='2e9d2c44-f675-40ba-8049-353bfcb5e171', -) - -bank_transactions_create_response = codat_lending.loan_writeback.bank_transactions.create(bank_transactions_create_request) -``` - - - - -```csharp -var bankTransactionsCreateResponse = await codatLending.LoanWriteback.BankTransactions.CreateAsync(new CreateBankTransactionsRequest() { - AccountingCreateBankTransactions = new AccountingCreateBankTransactions() { - AccountId = lendersBankAccount.Id, // Lender's virtual bank account ID you would have stored from the configuration step - Transactions = new List() { - new CreateBankAccountTransaction(){ - Id = transactionId, // Unique identifier for this bank transaction - Amount = feeAndInterestAmount, - date = feeAndInterestIssueDate, - description = description, // Include a reference to supplier and direct cost - }, - new CreateBankAccountTransaction(){ - Id = transactionId, // Unique identifier for this bank transaction - Amount = outstandingAmount, - Date = outstandingAmountTransferDate, - Description = description, // Include a reference to transfer - }, - new CreateBankAccountTransaction(){ - Id = transactionId, // Unique identifier for this bank transaction - Amount = invoiceAmount, - 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" -}); -``` - - - - -```go -ctx := context.Background() -bankTransactionsCreateRequest, err := codatLending.LoanWriteback.BankTransactions.Create(ctx, operations.CreateBankTransactionsRequest{ - AccountingCreateBankTransactions: &shared.AccountingCreateBankTransactions{ - AccountID: lending.String(lendersBankAccount.ID), // Lender's virtual bank account ID you would have stored from the configuration step - Transactions: []shared.CreateBankAccountTransaction{ - shared.CreateBankAccountTransaction{ - ID: lending.String(transactionID), // Unique identifier for this bank transaction - Amount: types.MustNewDecimalFromString(feeAndInterestAmount), - Date: lending.String(feeAndInterestIssueDate), - Description: lending.String(description), // Include a reference to supplier and direct cost - }, - shared.CreateBankAccountTransaction{ - ID: lending.String(transactionID), // Unique identifier for this bank transaction - Amount: types.MustNewDecimalFromString(outstandingAmount), - Date: lending.String(outstandingAmountTransferDate), - Description = lending.String(description), // Include a reference to transfer - }, - shared.CreateBankAccountTransaction{ - ID: lending.String(transactionID), // Unique identifier for this bank transaction - Amount: types.MustNewDecimalFromString(invoice.totalAmount), - Date: lending.String(invoicePaymentDate), - Description: lending.String(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", - }) -``` - - - - -```http -POST https://api.codat.io/companies/{companyId}/connections/{connectionId}/push/bankAccounts/{accountId}/bankTransactions -``` - -#### Request body - -```json -{ - "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 - }, - ] -} -``` - - - - -At the end of this 3-stage process, your borrower will have the loan writeback reflected correctly in their accounting software. This saves them time on reconciliation and makes sure they (and you!) have clarity on the state of the loan. - -:::tip 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. -::: - ---- - -## Read next - -* Check out our [invoice finance guide](/lending/guides/invoice-finance/introduction) to see how you can make automated decisions on selected invoices. -* Review other features of the [Lending API](/lending/overview). \ No newline at end of file diff --git a/docs/lending/overview.md b/docs/lending/overview.md index 23b30547a..84ec0efe6 100644 --- a/docs/lending/overview.md +++ b/docs/lending/overview.md @@ -141,7 +141,9 @@ Our Lending API empowers you with a host of features to help you streamline your ## Build with client libraries -Use our [comprehensive SDKs](/get-started/libraries) to kick-start and simplify your developers' journey automating the collection of your customers' financial data and making an assessment of a small business's financial health and performance. The SDKs come in multiple languages and provide sample requests and responses for the full range of lending and underwriting scenarios. +Use our [comprehensive SDKs](/get-started/libraries) to kickstart and simplify your developers' journey automating the collection of your customers' financial data and making an assessment of a small business's financial health and performance. + +Our Lending SDK comes in multiple languages and provides all the necessary methods to build your solution, enabling you to develop everything from a merchant capital product to loan writeback with just a single SDK. diff --git a/sidebars/lending.js b/sidebars/lending.js index 8eb1f9cdb..7a90ec1e7 100644 --- a/sidebars/lending.js +++ b/sidebars/lending.js @@ -45,7 +45,6 @@ module.exports = [ "lending/guides/loan-writeback/configure", "lending/guides/loan-writeback/deposit", "lending/guides/loan-writeback/record-general-loan", - "lending/guides/loan-writeback/record-invoice-finance", ], }, {