npm package: @hassanmehdi98/fineract-api-client
Description: TypeScript client for Fineract APIs
Author: Hassan Mehdi 98.hassanmehdi@gmail.com
Latest version: 0.1.4

# Fineract API Client

TypeScript client for interacting with specific Fineract client-related APIs.
This library provides type-safe methods for creating and retrieving client information from a Fineract instance.

## Installation

```bash
npm install @hayeeder/fineract-api-client
# or
yarn add @hayeeder/fineract-api-client
```

## Usage

First, configure and create an instance of the `FineractSDK`:

```typescript
import {
  createFineractSDK,
  FineractSDKConfig,
} from "@hayeeder/fineract-api-client";

const sdkConfig: FineractSDKConfig = {
  baseURL: "https://your-fineract-host.com", // Replace with your Fineract base URL
  tenantId: "default", // Your Fineract tenant ID
  username: "mifos", // Your Fineract username
  password: "password", // Your Fineract password
  timeout: 30000, // Optional: request timeout
};

const fineractSDK = createFineractSDK(sdkConfig);
```

### Example 1: Create a New Client

```typescript
import { CreateClientRequest } from "@hayeeder/fineract-api-client";

async function createNewClient() {
  const clientData: CreateClientRequest = {
    officeId: 1,
    fullname: "Jane Doe API",
    active: true,
    activationDate: "2024-07-28", // Use yyyy-MM-dd format
    dateFormat: "yyyy-MM-dd",
    locale: "en",
    legalFormId: 1, // Ensure this ID is valid in your Fineract setup
  };

  try {
    const response = await fineractSDK.client.createClient(clientData);
    console.log("Client Created:", response);
    // The actual ID of the created client is usually in response.resourceId or response.clientId
    const clientId = response.resourceId;
    if (clientId) {
      console.log("New Client ID:", clientId);
    }
  } catch (error) {
    console.error("Failed to create client:", error);
  }
}

createNewClient();
```

### Example 2: Get Client Details

```typescript
async function getClient(clientId: number) {
  try {
    const clientDetails = await fineractSDK.client.getClientDetails(clientId);
    console.log("Client Details:", clientDetails);
  } catch (error) {
    console.error(`Failed to get client ${clientId}:`, error);
  }
}

// Assuming a client with ID 123 exists
// getClient(123);
```

### Complete Client Creation Workflow

To successfully create a client and set up all required accounts and details, follow these steps using the relevant APIs from the SDK:

#### Step 1. Create the SME Client

- **API:** `fineractSDK.sme.create()`
- **Description:** Use the SME API to create a new client (SME) in Fineract.
- **Example:**

  ```typescript
  const smeResponse = await fineractSDK.sme.create({
    officeId: 1, // Hardcoded to 1 because currently we only have head office
    fullname: "Acme Corporation",
    active: true, // Hardcoded to always true
    activationDate: "2024-07-28", // Use yyyy-MM-dd format i.e. can be Today's date
    dateFormat: "yyyy-MM-dd",
    locale: "en",
    legalFormId: 2, // Hardcoded to 2 meaning client in fineract langauge
    externalId: "LOS-EXT-123456", // Replace with actual externalId i.e. masterCompanyId from LOS
  });
  const clientId = smeResponse.resourceExternalId; // external unique identifier i.e. externalId from LOS
  ```

#### 2. Add Virtual Account Number (Datatables API)

- **API:** `fineractSDK.datatable.addEntry(datatableName, entryData)`
- **Description:** Add virtual account number for the client using the Datatables API. The datatable name and required fields depend on your Fineract configuration.
- **Example:**
  ```typescript
  // adding virtual account number
  await fineractSDK.datatable.addEntry("dt_client_virtual_account_number", {
    client_id: clientId, // get the clientId with fineractSDK.client.getClientDetails(externalId) API
    virtualAccountNumber: 123456, // replace with actual virtual account number from LOS
  });
  ```

#### 2.1. Add Remitter Details (Datatables API) IMP: This step is only required for SMEs with RBF product enabled

- **API:** `fineractSDK.datatable.addEntry(datatableName, entryData)`
- **Description:** Add remitter details for the client using the Datatables API. The datatable name and required fields depend on your Fineract configuration.
- **Example:**
  ```typescript
  // adding remitter name
  await fineractSDK.datatable.addEntry("dt_client_remitter_names", {
    client_id: clientId, // get the clientId with fineractSDK.client.getClientDetails(externalId) API
    remitterName: "Remitter Name", // replace with actual remitter name from LOS
  });
  ```

#### 2.2. The 3-Step Process for Creating Savings Accounts

Creating any type of savings account (including Fallback, Cash Margin, or Collection accounts) is a three-step process. The account must be created, then approved, and finally activated to become fully functional.

1.  **Create:** Call `fineractSDK.savingsaccounts.create()` to create the account record. This returns a `savingsId`.
2.  **Approve:** Call `fineractSDK.savingsproducts.approve()` using the `savingsId`. This moves the account to an "approved" state.
3.  **Activate:** Call `fineractSDK.savingsproducts.activate()` using the `savingsId`. This makes the account "active" and ready for transactions.

- **API:** `fineractSDK.savingsaccounts.create()`, `fineractSDK.savingsproducts.approve()`, `fineractSDK.savingsproducts.activate()`
- **Description:** A complete workflow for creating, approving, and activating a savings account.
- **Example:**

  ```typescript
  // The ID of the client for whom the account is being created
  const clientId = 123;
  // The ID of the savings product (e.g., for a Fallback Account)
  const productId = 456;

  // Step 1: Create the savings account
  const savingsAccount = await fineractSDK.savingsaccounts.create({
    clientId: clientId,
    productId: productId,
    submittedOnDate: "2024-07-28", // Use current date
    dateFormat: "yyyy-MM-dd",
    locale: "en",
  });
  const savingsId = savingsAccount.savingsId;

  // Step 2: Approve the savings account
  const approvalResponse = await fineractSDK.savingsproducts.approve(
    savingsId,
    {
      approvedOnDate: "2024-07-28", // Use current date
      dateFormat: "yyyy-MM-dd",
      locale: "en",
    }
  );

  // Step 3: Activate the savings account
  const activationResponse = await fineractSDK.savingsproducts.activate(
    savingsId,
    {
      activatedOnDate: "2024-07-28", // Use current date
      dateFormat: "yyyy-MM-dd",
      locale: "en",
    }
  );

  console.log("Savings account created, approved, and activated successfully!");
  ```

#### 3. Create Fallback Account (Savings Account API)

- **API:** `fineractSDK.savingsaccounts.create()`
- **Description:** Every SME should have one fallback account at the time of creation. It is type of savings account which will be used to store funds which cannot be categorised.
- **Example:**
  ```typescript
  const fallbackAccount = await fineractSDK.savingsaccounts.create({
    clientId: clientId, // get the clientId with fineractSDK.client.getClientDetails(externalId) API
    productId: FALLBACK_PRODUCT_ID, // get all savings products with fineractSDK.savingsproducts.getAll() and filter by shortName=FBSA i.e. fallback savings account to get productId to be sent
    submittedOnDate: "2024-07-28", // This should be current date
    dateFormat: "yyyy-MM-dd",
    locale: "en",
  });
  const fallbackAccountId = fallbackAccount.resourceId;
  ```
  Make sure to approve and activate the account as described above

#### 4. Create Cash Margin Account (Savings Account API)

- **API:** `fineractSDK.savingsaccounts.create()`
- **Description:** Every SME should have cash margin account at the time of creation. It is type of savings account which will be used to store security deposits of 5%, 10% etc while disbursing loan
- **Example:**
  ```typescript
  const cashMarginAccount = await fineractSDK.savingsaccounts.create({
    clientId: clientId,
    productId: CASH_MARGIN_PRODUCT_ID, // get all savings products with fineractSDK.savingsproducts.getAll() and filter by shortName=CMSA i.e. cash margin savings account
    dateFormat: "yyyy-MM-dd",
    locale: "en",
  });
  const cashMarginAccountId = cashMarginAccount.resourceId;
  ```
  Make sure to approve and activate the account as described above

---

**Summary of Steps and APIs:**

1. **Create SME Client:** `fineractSDK.sme.create()`
2. **Add Virtual Account & Remitter Details:** `fineractSDK.datatable.addEntry()`
3. **Create Fallback Savings Account:** `fineractSDK.savingsaccounts.create()`
4. **Create Cash Margin Savings Account:** `fineractSDK.savingsaccounts.create()`

> **Note:** Replace datatable names, product IDs, and field names as per your Fineract instance configuration.

**Important API Paths:**
The API paths used in this SDK (`/fineract-provider/api/v1/clients` and `/fineract-provider/api/v1/clients/{clientId}`) are based on common Fineract setups and the provided `clients.ts` example. You **must verify** these paths against your Fineract instance's API documentation or the underlying `ClientApi` implementation you were using. You may need to adjust these paths in `src/api/fineract-client-api.ts` if they differ.

### How to get repayment schedule without creating loan

#### 1. Calculate Loan Repayment Schedule (Loan Accounts API)

- **API:** `fineractSDK.loansaccounts.getRepaymentSchedule()`
- **Description:** Calculate and retrieve the repayment schedule for a loan before actually creating the loan account. This is useful for showing the user the expected repayment plan based on their input parameters.
- **Example:**

  ```typescript
  const repaymentSchedule =
    await fineractSDK.loansaccounts.getRepaymentSchedule({
      productId: 1, // get all loan products with fineractSDK.loanproducts.getAll() and filter by externalId=REVENUE_BASED_FINANCING
      submittedOnDate: "28 May 2025", // Date the loan application is submitted
      expectedDisbursementDate: "30 May 2025", // Expected date of disbursement
      loanTermFrequency: 3, // Number of periods (e.g., months)
      loanTermFrequencyType: 2, // Frequency type (0=Days, 1=Weeks, 2=Months, 3=Years)
      numberOfRepayments: 3, // Total Number of installments to repay: Used like every [repaymentEvery] [repaymentFrequencyType] for [numberOfRepayments]
      repaymentEvery: 1, // Repayment interval (e.g., every 1 month)
      repaymentFrequencyType: 2, // Repayment frequency type (0=Days, 1=Weeks, 2=Months, 3=Years)
      interestType: 0, // Interest type (0 = flat, 1 = declining balance)
      amortizationType: 1, // Amortization type (0=Equal principle payments, 1=Equal installments) - Fetch this from loan product details in amortizationType.id
      interestCalculationPeriodType: 3, // Interest calculation period type - Fetch this from loan product details in interestCalculationPeriodType.id
      interestRatePerPeriod: 1, // Interest rate per period -> 1 means 10%
      transactionProcessingStrategyCode: "mifos-standard-strategy", // Hardcoded to mifos-standard-strategy
      dateFormat: "yyyy-MM-dd", // Hardcoded to yyyy-MM-dd - Date format used in the request
      locale: "en", // Locale
      clientId: 1, // // get the clientId with fineractSDK.client.getClientDetails(externalId) API
      loanType: "individual", // Type of loan
      principal: 100000, // Principal amount - Input from LOS
    });
  console.log(
    "Repayment Schedule:",
    JSON.stringify(repaymentSchedule, null, 2)
  );
  ```

- **API Path Used:** `/fineract-provider/api/v1/loans?command=calculateLoanSchedule`
- **Reference:** See [`src/api/fineract-loansaccounts-api.ts`](src/api/fineract-loansaccounts-api.ts) and [`src/types/loansaccounts.ts`](src/types/loansaccounts.ts) for full request/response details.

> **Note:** This API does not create a loan, it only returns the calculated schedule based on the input parameters. Use this to preview repayment plans before submitting a loan application.

### How to create loan application for SME

#### 1. Create RBF collection account (Savings Account API)

- **API:** `fineractSDK.savingsaccounts.create()`
- **Description:** Every SME should have collection account based on product at the time of creation. It is type of savings account which will be save funds collected from SME. For each Loan Account i.e Loan Application, we must have corresponding collection account
- **Example:**
  ```typescript
  const cashMarginAccount = await fineractSDK.savingsaccounts.create({
    clientId: clientId,
    productId: RBF_COLLECTION_ACCOUNT, // get all savings products with fineractSDK.savingsproducts.getAll() and filter by shortName=RBF i.e. Rbf collection savings account
    dateFormat: "yyyy-MM-dd",
    locale: "en",
  });
  const cashMarginAccountId = cashMarginAccount.resourceId;
  ```
  Make sure to approve and activate the account as described above

#### 2. Create Loan Account (Loan Accounts API)

- **API:** `fineractSDK.loansaccounts.create()`
- **Description:** Create a new loan account for a client in Fineract. This will actually create the loan in the system and return the created loan's details.
- **Example:**

  ```typescript
  const newLoan = await fineractSDK.loansaccounts.create({
    productId: 1, // get all loan products with fineractSDK.loanproducts.getAll() and filter by filter by externalId=REVENUE_BASED_FINANCING
    linkAccountId: 123, // ID of the collection account you created above
    submittedOnDate: "28 May 2025", // Date the loan application is submitted
    expectedDisbursementDate: "30 May 2025", // Expected date of disbursement - can be anything in future
    loanTermFrequency: 3, // Number of periods (e.g., months)
    loanTermFrequencyType: 2, // Frequency type (0=Days, 1=Weeks, 2=Months, 3=Years)
    numberOfRepayments: 3, // Total Number of installments to repay: Used like every [repaymentEvery] [repaymentFrequencyType] for [numberOfRepayments]
    repaymentEvery: 1, // Repayment interval (e.g., every 1 month)
    repaymentFrequencyType: 2, // Repayment frequency type (0=Days, 1=Weeks, 2=Months, 3=Years)
    interestType: 0, // Interest type (0 = flat, 1 = declining balance)
    amortizationType: 1, // Amortization type (0=Equal principle payments, 1=Equal installments) - Fetch this from loan product details in amortizationType.id
    interestCalculationPeriodType: 1, // Interest calculation period type - Fetch this from loan product details in interestCalculationPeriodType.id
    transactionProcessingStrategyCode: "mifos-standard-strategy", // Hardcoded to mifos-standard-strategy
    interestRatePerPeriod: 1, // Interest rate per period -> 1 means 10%
    dateFormat: "yyyy-MM-dd", // Hardcoded to yyyy-MM-dd - Date format used in the request
    locale: "en", // Locale
    clientId: 1, // // get the clientId with fineractSDK.client.getClientDetails(externalId) API
    loanType: "individual", // Type of loan
    principal: 100000, // Principal amount
  });
  console.log("Loan Created:", JSON.stringify(newLoan, null, 2));
  ```

- **API Path Used:** `/fineract-provider/api/v1/loans`
- **Reference:** See [`src/api/fineract-loansaccounts-api.ts`](src/api/fineract-loansaccounts-api.ts) and [`src/types/loansaccounts.ts`](src/types/loansaccounts.ts) for full request/response details.

> **Note:** This API will create a loan account in Fineract. Make sure all required fields are provided and valid as per your Fineract instance configuration.

### How to get loan application data from Fineract to show on SME dashboard

- **API:** `fineractSDK.loanaccounts.getSummaryById()`
- **Description:** Get loan summary information from Fineract
- **Example:**

  ```typescript
  const loan = await fineractSDK.loanaccounts.getSummaryById(123);
  console.log("Loan:", JSON.stringify(loan, null, 2));

  const totalDisbursedAmount = loan.netDisbursalAmount;
  const totalOutstandingAmount = loan.summary.totalOutstanding;
  const interestRate = loan.annualInterestRate;
  const duration = loan.termFrequency;
  const durationUnit = loan.termPeriodFrequencyType.value;
  // To get next due payment
  const [year, month, day] = loan.delinquent.nextPaymentDueDate;
  ```

  This will return you the information of the loan summary you need to show on SME dashboard for a given loan application.

  ### How to get loan application schedule from Fineract to show on SME dashboard per loan application

- **API:** `fineractSDK.loanaccounts.getRepaymentScheduleById()`
- **Description:** Get loan repayment schedule information from Fineract
- **Example:**

  ```typescript
  const loan = await fineractSDK.loanaccounts.getRepaymentScheduleById(123);
  console.log("Loan:", JSON.stringify(loan, null, 2));

  const loanAmount = loan.approvedPrincipal;
  const totalOutstandingAmount = loan.summary.totalOutstanding;
  const interestRate = loan.annualInterestRate;
  const duration = loan.termFrequency;
  const durationUnit = loan.termPeriodFrequencyType.value;

  // To get Issued on date
  const [year, month, day] = loan.timeline.actualDisbursementDate;

  // Repayment periods, first item in the array is always the disbursement information which we ignore
  const schedule = loan.repaymentSchedule.periods;

  // Follow this for all items, except for the index 0
  const amount = schedule[1].totalInstallmentAmountForPeriod;
  const [dueYear, dueMonth, dueDay] = schedule[1].dueDate;
  const remaining = schedule[1].totalOutstandingForPeriod;
  const status = schedule[1].status;
  ```

  This will return you the information of the loan summary along with repayment schedule

## Development

- Build: `npm run build`
- Test: `npm run test`
- Lint: `npm run lint`
- Run Examples: `npm run dev` (Ensure you update `src/examples/run-examples.ts` with your Fineract instance details)
- Generate Docs: `npm run build:docs` (Output in `docs/` folder)

## Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

Please make sure to update tests as appropriate.

## License

[MIT](LICENSE)