{ "title": "How FundFlow Matches Angel Investors with Kenya Startups: The Technical Deep Dive", ...
{"title":"How FundFlow Matches Angel Investors with Kenya Startups: The Technical Deep Dive","content":"# How FundFlow Matches Angel Investors with Kenya Startups: The Technical Deep Dive\n\nKenyan startups raise roughly $400M annually, but here's the brutal truth: most never meet a single angel investor. Why? The infrastructure doesn't exist. There's no standardized way for a founder in Kisumu to connect with an angel in Nairobi who invests in fintech. There's no API layer connecting Kenya's fragmented investor networks.\n\nThis is what FundFlow's engineering team built. We're a Kenyan tech company solving one of Africa's hardest problems: *how do you programmatically match founders with the right capital, over unreliable networks, in markets where investor data is fragmented?*\n\nLet's talk about how we did it.\n\n## The Problem: Africa's Unique Infrastructure Constraints\n\nBefore we wrote a single line of code, we had to understand our constraints:\n\n- **Network reliability**: Kenya's mobile networks have ~95% uptime in urban areas, ~65% in rural areas. Your API calls might timeout. Your database connection might drop mid-transaction.\n- **Data fragmentation**: Angel investor data lives in spreadsheets, WhatsApp groups, LinkedIn, and closed Facebook communities. There's no central registry.\n- **Mobile-first users**: 60M+ Kenyans use M-Pesa daily. Most founders checking their funding status do it on a 3G connection from a matatu.\n- **Cost sensitivity**: Every API call, every database query, every megabyte of data costs real money.\n\nThis shaped every architectural decision we made.\n\n## FundFlow's Architecture: API-First Design\n\nWe built FundFlow around three core services:\n\n```
\nβββββββββββββββββββββββββββββββββββββββββββ\nβ Mobile Client Layer β\nβ (React Native + offline-first) β\nββββββββββββββββ¬βββββββββββββββββββββββββββ\n β\nββββββββββββββββΌβββββββββββββββββββββββββββ\nβ API Gateway (Kong) β\nβ Rate limiting, circuit breakers β\nββββββββββββββββ¬βββββββββββββββββββββββββββ\n β\n ββββββββββββΌβββββββββββ\n β β β\nβββββΌβββ ββββββΌββββ ββββΌβββββ\nβMatch β βProfile β βPaymentβ\nβ API β β API β βAPI β\nβββββ¬βββ ββββββ¬ββββ ββββ¬βββββ\n β β β\nβββββ΄βββββββββββ΄ββββββββββ\n β\n βββββΌββββββββββββββββββ\n β PostgreSQL + Redis β\n β (Replication ready) β\n ββββββββββββββββββββββββ\n
```\n\n**Why this design?**\n\n1. **Kong API Gateway**: Handles rate limiting (crucial when your user base jumps from 1,000 to 50,000 overnight). Implements circuit breakers so if our investor-matching service slows down, we don't cascade failures across other services.\n\n2. **Microservices**: Decoupled services mean we can scale the matching engine independently from payment processing. If M-Pesa integration gets hammered, our matching API stays responsive.\n\n3. **Offline-first mobile**: The app syncs investor profiles and portfolio data when connection is available. When it's not, founders can still browse matches and draft pitches.\n\n## The Matching Algorithm: Building a Smart Recommendation Engine\n\nHere's where it gets interesting. We couldn't use off-the-shelf recommendation engines because:\n\n- Investor data is sparse and incomplete\n- Investors in Kenya have deep domain expertise but no standardized way to tag it\n- Success is binary: did the investor actually fund this startup?\n\nWe built a hybrid approach:\n\n```
python\n# Simplified version of our matching algorithm\nfrom enum import Enum\nfrom typing import List, Tuple\n\nclass InvestorType(Enum):\n ANGEL = \"angel\"\n MICRO_VC = \"micro_vc\"\n CORPORATE = \"corporate\"\n\nclass StartupProfile:\n def __init__(self, founder_id, sector, stage, amount_seeking, location):\n self.founder_id = founder_id\n self.sector = sector # fintech, agritech, etc.\n self.stage = stage # pre-seed, seed, series-a\n self.amount_seeking = amount_seeking # KES\n self.location = location # Nairobi, Kisumu, etc.\n self.pitch_sentiment = None\n self.team_quality_score = None\n\nclass InvestorProfile:\n def __init__(self, investor_id, sector_focus, check_size, location):\n self.investor_id = investor_id\n self.sector_focus = sector_focus # tags: [\"fintech\", \"climate\"]\n self.check_size = check_size # (min_kes, max_kes)\n self.location = location\n self.portfolio_quality_score = None\n\ndef calculate_match_score(\n startup: StartupProfile,\n investor: InvestorProfile\n) -> Tuple[float, dict]:\n\"\"\"\n Multi-factor matching score (0-100).\n Weights tuned from 2 years of real funding data.\n\"\"\"\n score = 0.0\n factors = {}\n\n # Factor 1: Sector alignment (40% weight)\n if startup.sector in investor.sector_focus:\n sector_score = 40.0\n else:\n sector_score = 10.0\n score += sector_