Agricultural credit remains under-distributed in Africa: only 5-10% of farmers access formal financing. Traditional banks refuse (no collateral, obsolete scoring). But with mobile money + satellite data + ML, alternative scoring becomes viable. Potential market: $5-15 billion.
TL;DR
- Alternative scoring based on: mobile money history + plot data + weather + past repayment behavior.
- Stack: Next.js + Python ML pipeline + Mono Connect + Sentinel-2 satellite.
- ROI: 3-8% NPL vs 15-25% traditional agricultural credit.
Scoring data sources
| Source | Indicator | Scoring weight |
|---|---|---|
| 12-month mobile money | Inflow/outflow volume, regularity | 30% |
| Repayment history | Past credits (cooperative, MFI) | 25% |
| Satellite plot data | NDVI, surface, estimated productivity | 20% |
| Regional weather | Anticipated water stress | 10% |
| Agri social network | Cooperative, recommendations | 10% |
| Demographics | Age, activity tenure | 5% |
Scoring architecture
`
[Farmer credit application]
↓
[Multi-source data collection]
├── Mobile money (Mono Connect Wave/MTN)
├── MFI history (partner network)
├── Plot GPS + NDVI (satellite)
├── Weather CHIRPS / NASA POWER
└── Cooperative profile
↓
[Python ML Pipeline]
├── Feature engineering
├── XGBoost classifier
├── Risk score 0-1000
└── PD (probability default) 0-1
↓
[Decision: approved / rejected / conditional]
↓
[Wave/MTN disbursement]
↓
[Automated repayment tracking]
`
Step 1 — data model
`prisma
model LoanApplication {
id String @id @default(cuid())
producerId String
amountRequested Int
durationMonths Int
purpose String
status String
riskScore Int?
pdEstimate Float?
approvedAmount Int?
approvedRate Float?
collateral Json?
mobileMoneyData Json?
parcelData Json?
weatherData Json?
cooperativeRefs Json?
decidedAt DateTime?
decidedBy String?
disbursedAt DateTime?
dueDate DateTime?
repaidAt DateTime?
defaultedAt DateTime?
}
`
Step 2 — mobile money collection via Mono Connect
`ts
async function collectMobileMoneyData(producerId: string) {
const producer = await prisma.producer.findUnique({ where: { id: producerId } });
// Farmer connects Wave/MTN account via Mono Connect
// See Open Banking Africa →
const transactions = await mono.account.transactions(producer.monoAccountId, {
start: addMonths(new Date(), -12).toISOString(),
end: new Date().toISOString(),
});
const features = {
avgMonthlyInflow: average(byMonth(transactions, 'CREDIT')),
avgMonthlyOutflow: average(byMonth(transactions, 'DEBIT')),
inflowVariability: stdDev(byMonth(transactions, 'CREDIT')),
monthsActive: countDistinctMonths(transactions),
seasonalityScore: detectSeasonality(transactions),
largeTransactionsCount: transactions.filter(t => t.amount > 100000).length,
pendingDebtsRatio: computeDebtRatio(transactions),
};
return features;
}
`
Step 3 — satellite plot analysis
`ts
async function analyzeParcelle(plot: Plot) {
const ndviTimeSeries = await fetchNDVITimeSeries({
lat: plot.gpsLat,
lng: plot.gpsLng,
bufferM: 50,
startDate: addYears(new Date(), -2),
endDate: new Date(),
});
return {
avgNDVI: mean(ndviTimeSeries.map(p => p.ndvi)),
ndviTrend: linearRegression(ndviTimeSeries).slope,
productivityEstimate: estimateYield(ndviTimeSeries, plot.productType),
Need a professional website?
Kolonell builds websites that attract clients, optimized for the Sénégalese market. Free quote in 2 minutes.
waterStressDays: countWaterStressDays(ndviTimeSeries),
surfaceHa: plot.surfaceHa,
};
}
`
Step 4 — ML scoring (Python)
`python
import xgboost as xgb
import pandas as pd
import joblib
def train_model(historical_loans_df):
"""Train XGBoost on historical agri credits with known outcomes."""
features = [
'mm_avg_monthly_inflow',
'mm_inflow_variability',
'mm_months_active',
'mm_seasonality_score',
'parcel_avg_ndvi',
'parcel_ndvi_trend',
'parcel_productivity_estimate',
'parcel_surface_ha',
'mfi_loans_count',
'mfi_repaid_on_time_ratio',
'producer_age',
'years_farming',
'cooperative_member',
'rainfall_avg_5y',
'drought_events_5y',
]
X = historical_loans_df[features]
y = historical_loans_df['defaulted']
model = xgb.XGBClassifier(
n_estimators=200,
max_depth=6,
learning_rate=0.05,
)
model.fit(X, y)
joblib.dump(model, 'agri_scoring_v2.joblib')
return model
def predict_pd(features):
"""Predict probability of default 0-1"""
model = joblib.load('agri_scoring_v2.joblib')
pd_estimate = model.predict_proba([features])[0][1]
risk_score = int((1 - pd_estimate) * 1000)
return {'risk_score': risk_score, 'pd_estimate': pd_estimate}
`
Step 5 — disbursement and tracking
`ts
async function disburseLoan(applicationId: string) {
const app = await prisma.loanApplication.findUnique({
where: { id: applicationId },
include: { producer: true },
});
await wavePayout({
receiverMsisdn: app.producer.walletNumber,
amount: app.approvedAmount,
currency: 'XOF',
narration: Agricultural credit #${app.id},
externalId: app.id,
});
const installments = generateInstallments(app);
for (const inst of installments) {
await prisma.loanInstallment.create({
data: {
loanId: app.id,
amount: inst.amount,
dueDate: inst.dueDate,
status: 'PENDING',
},
});
}
await scheduleReminders(app.id);
}
`
Real case — CrediTerra Senegal startup
Profile: 4,200 financed farmers in 18 months.
| Metric | Value |
|---|---|
| Disbursed credits | 4,200 (4M-150K XOF each) |
| Total disbursed | 1.8 billion XOF |
| Average interest rate | 22% annual (vs bank 18%, MFI 28-35%) |
| NPL (Non-Performing Loans) | 5.8% |
| Gross margin | 14% |
| Recurring farmers | 64% |
Compare traditional agri bank NPL: 18-28%.
Common pitfalls
- Over-financing without capacity — watch risk profile. ML model conservative at start.
- Disbursement without follow-up — D-7, D-3, D0 reminders = -40% NPL.
- Desynced wallet cache — if Wave revokes, Mono loses access. Re-prompt farmer.
- No hybrid collateral — crop insurance (Pula, Acre Africa) coupled with credit = mutualized risk.
- BCEAO compliance — EME approval or bank partnership for IMF declarations.
FAQ
Q: Interested investors?
A: Acumen Fund, Mercy Corps Ventures, Sycamore Ventures (Africa AgriTech). $500K-3M seed capital.
Q: Competition?
A: Pula, Apollo Agriculture (KE), Babban Gona (NG), Aerobotics (ZA). Francophone less saturated.
Q: Regulation?
A: BCEAO frames MFIs + EMEs in UEMOA. SN Law 2018-23 on digital financial services.
Conclusion
Digital agricultural credit with alternative scoring = massive 2026 Africa opportunity. $1-3M seed investment for solid stack. 24-36 month ROI on clean execution + portfolio quality. Measurable social impact + viable business.
Mohamed Bah
Fondateur, Kolonell
Passionate about digital and entrepreneurship in Africa, Mohamed has been helping Sénégalese businesses with their digital transformation since 2020. Founder of Kolonell, he believes every SME deserves a professional and accessible online présence.