Language SDKs
SaaS tenant. The MFI Suite is delivered as a fully managed service — there is nothing to install or configure at the OS level. Self-hosted one-time licence buyers receive a dedicated installation runbook with the licence delivery; this page describes the user-facing workflow only.
Use a language SDK instead of raw HTTP. Each SDK handles OAuth refresh, retries, idempotency keys, pagination, and typed responses so your application code stays clean.

At a glance — Python: (install instructions are in each SDK's README; pick your language below). Node: npm install @bridgeerp/mfi-sdk. Java: Maven com.bridgeerp:mfi-sdk:1.x. Go: go get github.com/bridgeerp/mfi-sdk-go. All SDKs versioned 1.x against API v1; 2.x for v2.
Python SDK
from mfi_sdk import MfiClient
client = MfiClient(
base_url='https://microfinance.mybridgeerp.com',
client_id='svc_kcb_disbursement',
client_secret='...',
scopes=['loans:read', 'disbursements:write'],
)
# List loans
for loan in client.loans.list(state='ready_to_disburse'):
print(loan.id, loan.member_name, loan.principal)
# Create member with idempotency
member = client.members.create(
name='Jane Wambui Mwangi',
national_id='22748561',
phone='+254712345678',
branch_id=3,
idempotency_key='jane-wambui-2026-03-15',
)
# Disburse
disb = client.loans.disburse(
loan_id=9183,
amount=5000000,
channel='mpesa_b2c',
msisdn='+254712345678',
idempotency_key='disburse-9183-2026-03-15',
)
Node.js SDK
import { MfiClient } from '@bridgeerp/mfi-sdk';
const client = new MfiClient({
baseUrl: 'https://microfinance.mybridgeerp.com',
clientId: 'svc_kcb_disbursement',
clientSecret: process.env.MFI_SECRET,
scopes: ['loans:read', 'disbursements:write'],
});
// List loans (async iterator handles pagination)
for await (const loan of client.loans.list({ state: 'ready_to_disburse' })) {
console.log(loan.id, loan.memberName, loan.principal);
}
// Create member
const member = await client.members.create({
name: 'Jane Wambui Mwangi',
nationalId: '22748561',
phone: '+254712345678',
branchId: 3,
}, { idempotencyKey: 'jane-wambui-2026-03-15' });
// Verify webhook signature
import { verifyWebhook } from '@bridgeerp/mfi-sdk';
const ok = verifyWebhook(rawBody, signature, secret);
Java SDK
// pom.xml
// <dependency>
// <groupId>com.bridgeerp</groupId>
// <artifactId>mfi-sdk</artifactId>
// <version>1.4.0</version>
// </dependency>
MfiClient client = MfiClient.builder()
.baseUrl("https://microfinance.mybridgeerp.com")
.clientId("svc_kcb_disbursement")
.clientSecret(System.getenv("MFI_SECRET"))
.scopes(List.of("loans:read", "disbursements:write"))
.build();
List<Loan> loans = client.loans()
.list()
.state("ready_to_disburse")
.execute();
Member member = client.members().create(
MemberCreate.builder()
.name("Jane Wambui Mwangi")
.nationalId("22748561")
.phone("+254712345678")
.branchId(3)
.build(),
RequestOptions.builder()
.idempotencyKey("jane-wambui-2026-03-15")
.build()
);
Go SDK
package main
import (
"context"
"log"
"github.com/bridgeerp/mfi-sdk-go"
)
func main() {
client := mfi.NewClient(mfi.Config{
BaseURL: "https://microfinance.mybridgeerp.com",
ClientID: "svc_kcb_disbursement",
ClientSecret: os.Getenv("MFI_SECRET"),
Scopes: []string{"loans:read", "disbursements:write"},
})
ctx := context.Background()
loans, err := client.Loans.List(ctx, &mfi.LoanListParams{State: mfi.String("ready_to_disburse")})
if err != nil { log.Fatal(err) }
for _, l := range loans.Data {
log.Printf("%d %s %d", l.ID, l.MemberName, l.Principal)
}
member, err := client.Members.Create(ctx, &mfi.MemberCreateParams{
Name: "Jane Wambui Mwangi",
NationalID: "22748561",
Phone: "+254712345678",
BranchID: 3,
}, mfi.RequestOptions{IdempotencyKey: "jane-wambui-2026-03-15"})
}
Common SDK features
- Automatic OAuth token caching and refresh
- Exponential backoff on 429 and 5xx
- Idempotency-Key support on all mutating methods
- Webhook signature verification helper
- Pluggable HTTP client for proxy / TLS customisation
- Pluggable logger for structured request/response logging
- Typed response models — full IDE auto-complete
- Async iterators / streams for pagination
Worked scenarios
Scenario — Nightly disbursement job in Node.js
| Character | Role |
|---|---|
| Samuel Kibet | DevOps Engineer |
| Peter Otieno | Operations Manager |
| Jane Wambui | Borrower (first run) |
Timeline
- Day 0, 14:00: Samuel writes job in TypeScript using SDK. (Job runs as Docker container on cron schedule.)
- Day 0, 18:00: Peter approves 23 loans during business close. (Loans state=ready_to_disburse, total KES 4.2M.)
- Day 1, 02:00: Cron fires. (SDK pulls 23 loans via async iterator.)
- Day 1, 02:00:30: SDK posts 23 disbursements with unique idempotency keys. (All 23 sent to M-Pesa B2C.)
- Day 1, 02:01: M-Pesa STK Push completes for Jane. (Webhook loan.disbursed fires; SMS dispatched.)
- Day 1, 02:03: All 23 disbursed. (Job logs success; alert if any failed.)
- Day 1, 06:00: Jane sees credit in her M-Pesa. (Receipt ref PBJ4S6X9DC linked to loan L-2026-09183.)
Outcome — End-to-end nightly disbursement automated in 40 lines of TypeScript. Idempotency keys make the job safely retryable on transient failure.
Reference
SDK version compatibility
| SDK | Latest | API version | Min runtime |
|---|---|---|---|
| mfi-sdk (Python) | 1.5.0 | v1 | Python 3.10+ |
| @bridgeerp/mfi-sdk (Node) | 1.4.2 | v1 | Node 18+ |
| com.bridgeerp:mfi-sdk (Java) | 1.4.0 | v1 | Java 17+ |
| github.com/bridgeerp/mfi-sdk-go | 1.3.0 | v1 | Go 1.21+ |
Common config options
| Option | Default | Description |
|---|---|---|
| baseUrl | (required) | Tenant base URL |
| clientId / clientSecret | (required) | OAuth credentials |
| scopes | all granted to client | Subset to request |
| timeout | 30s | HTTP request timeout |
| maxRetries | 3 | Retry budget for 429/5xx |
| userAgent | mfi-sdk/ | HTTP User-Agent |
| proxy | none | HTTP proxy URL |
| logger | stdout (debug off) | Structured logger |
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| SDK throws 'token refresh failed' under load. | Race condition refreshing token across many threads. | Upgrade SDK to latest (token refresh now mutex-guarded). |
| Pagination iterator never terminates. | Tenant returning malformed cursor. | File a bug with reproduction; workaround: pass limit and iterate manually. |
| Webhook verifier rejecting valid signatures. | Body parsed before passing to verifier (body must be raw bytes). | Use raw request body, not parsed JSON, for HMAC computation. |
See also
Was this page helpful?

