Eighty-six sessions built the foundation. The next eighty-six sessions will build the future. 0fee.dev launched with one-time payments across 53+ providers in 200+ countries. But a payment orchestrator that only handles one-time payments is only solving half the problem.
This article lays out the roadmap -- informed by the security audit findings, feature request submissions from early users, and the gaps we identified during the build process. Each item represents a real need, not a speculative feature.
Subscription and Recurring Payments
The most requested feature from early adopters. Subscriptions require a fundamentally different payment model:
python# Planned: Subscription model
class Subscription(Base):
__tablename__ = "subscriptions"
id = Column(String, primary_key=True)
app_id = Column(String, ForeignKey("apps.id"), nullable=False)
customer_id = Column(String, nullable=False)
plan_id = Column(String, nullable=False)
# Billing configuration
amount = Column(Float, nullable=False)
currency = Column(String(3), nullable=False)
interval = Column(String, nullable=False) # daily, weekly, monthly, yearly
interval_count = Column(Integer, default=1) # e.g., every 2 months
# State
status = Column(String, default="active") # active, paused, cancelled, past_due
current_period_start = Column(DateTime)
current_period_end = Column(DateTime)
cancel_at_period_end = Column(Boolean, default=False)
# Retry logic
retry_count = Column(Integer, default=0)
max_retries = Column(Integer, default=3)
last_retry_at = Column(DateTime, nullable=True)The challenge with subscriptions in the African market is that many customers use mobile money, which does not support automatic recurring charges. The subscription engine will need to handle:
- Card-based: Automatic charges via stored card tokens (Stripe, PayPal)
- Mobile money push: Send a payment request to the customer's phone at each billing cycle
- Manual renewal: Send an invoice/payment link for the customer to pay manually
Each billing cycle, the subscription engine will attempt the preferred method first, fall back to alternatives, and escalate to manual renewal if automated methods fail.
Payout and Disbursement API
0fee.dev currently handles pay-ins (collecting money). Payouts -- sending money to merchants, suppliers, or individuals -- are the logical complement:
python# Planned: Payout API
@router.post("/payouts")
async def create_payout(data: PayoutCreate):
"""Send money to a bank account or mobile money wallet."""
# Validate recipient
# Route to appropriate provider
# Execute payout
# Track status
pass
class PayoutCreate(BaseModel):
amount: float
currency: str
recipient: PayoutRecipient # Bank account or mobile money number
reference: str
description: str | None = None
class PayoutRecipient(BaseModel):
type: str # bank_account, mobile_money
# Bank account fields
bank_code: str | None = None
account_number: str | None = None
# Mobile money fields
phone_number: str | None = None
provider: str | None = None # orange, mtn, wave
country: str | None = NonePayouts in Africa are particularly important for: - Marketplace platforms: Paying sellers after a sale - Gig economy apps: Paying workers daily or weekly - Remittances: Sending money between countries - Salary disbursement: Paying employees via mobile money
The provider adapter pattern we established in Session 001 will serve us well here. Each payout provider implements the same interface, and the routing engine selects the best path based on country, method, and cost.
Dispute Management
When a customer disputes a payment (chargeback), the merchant needs tools to respond. Currently, disputes are handled entirely through the underlying provider's dashboard (e.g., Stripe's dispute interface). We plan to centralize dispute management:
python# Planned: Dispute model
class Dispute(Base):
__tablename__ = "disputes"
id = Column(String, primary_key=True)
transaction_id = Column(String, ForeignKey("transactions.id"), nullable=False)
provider_dispute_id = Column(String, nullable=True)
reason = Column(String) # fraudulent, duplicate, product_not_received, etc.
status = Column(String) # open, under_review, won, lost, accepted
amount = Column(Float)
currency = Column(String(3))
evidence_due_by = Column(DateTime, nullable=True)
evidence_submitted = Column(Boolean, default=False)
created_at = Column(DateTime, server_default=func.now())
resolved_at = Column(DateTime, nullable=True)The dispute management system will: - Aggregate disputes from all providers into a single dashboard - Send notifications when new disputes are filed - Provide a structured evidence submission flow - Track dispute outcomes and win rates - Calculate dispute rate per merchant (important for provider compliance)
Advanced Analytics
The current analytics are basic: volume, count, success rate. The next iteration will provide actionable insights:
Conversion funnel analysis: Where do customers drop off? After selecting a payment method? During 3D Secure? At the provider's checkout page?
Provider performance comparison: For the same country and payment method, which provider has the highest success rate, lowest latency, and least failures?
Revenue forecasting: Based on historical transaction patterns, what revenue can merchants expect next month?
Anomaly detection: Alert when transaction patterns deviate significantly from baseline (potential fraud, system issues, or provider outages).
Provider Health Monitoring
Identified in the security audit as a critical gap. When a provider goes down, the routing engine should automatically reroute payments to an alternative:
python# Planned: Provider health monitoring
class ProviderHealthCheck(Base):
__tablename__ = "provider_health_checks"
id = Column(String, primary_key=True)
provider_name = Column(String, nullable=False)
status = Column(String) # healthy, degraded, down
latency_ms = Column(Integer)
success_rate_1h = Column(Float) # Last hour success rate
last_checked_at = Column(DateTime)
last_incident_at = Column(DateTime, nullable=True)
async def health_aware_routing(payment_data: dict) -> BaseProvider: """Route payments considering provider health.""" candidates = get_available_providers(payment_data) BLANK for provider in candidates: health = await get_provider_health(provider.name) if health.status == "down": continue # Skip entirely if health.status == "degraded": provider.priority -= 10 # Deprioritize but allow BLANK return select_best_provider(candidates) ```
The health monitoring system will check providers every 60 seconds with lightweight API calls. When a provider's success rate drops below 80% over a 5-minute window, it is marked as degraded. Below 50%, it is marked as down.
More African Providers
The current provider roster covers Africa broadly but lacks depth in specific markets:
M-Pesa Deep Integration
M-Pesa is the dominant mobile money provider in East Africa (Kenya, Tanzania, Mozambique). The current integration through PawaPay works but does not expose M-Pesa-specific features:
- M-Pesa STK Push: Automated payment prompt sent directly to the customer's phone
- M-Pesa B2C: Business-to-customer payouts
- M-Pesa Bill Manager: Recurring bill payments
- M-Pesa Till/Paybill: Direct merchant integration
Airtel Money
Airtel Money operates in 14 African countries. It is the second-largest mobile money provider on the continent. Direct Airtel Money integration would provide:
- Lower fees than going through aggregators
- Faster settlement times
- Country-specific features (Airtel Money Uganda is different from Airtel Money Kenya)
Regional Payment Providers
| Provider | Market | Status |
|---|---|---|
| Flutterwave | Pan-African | Planned |
| Chipper Cash | 7 African countries | Under evaluation |
| MFS Africa | Cross-border mobile money | Under evaluation |
| Paga | Nigeria | Under evaluation |
| GTBank (GTPay) | Nigeria | Under evaluation |
| Equity Bank | Kenya | Under evaluation |
The AI Developer Assistant
Claude Haiku integration for in-dashboard developer support:
typescript// Planned: AI Developer Assistant widget
<AiAssistant
context={{
app: currentApp,
recentErrors: last10Errors,
integrationStatus: providerStatuses,
}}
systemPrompt={`You are the 0fee.dev developer assistant.
Help the developer integrate payment providers,
debug failed transactions, and optimize their setup.`}
/>The assistant will: - Answer questions about 0fee.dev's API using the documentation as context - Help debug failed transactions by analyzing error patterns - Suggest optimal provider configurations based on the merchant's country mix - Generate code snippets in the merchant's preferred language - Explain webhook payloads and help set up webhook handlers
Multi-Currency Wallets
Currently, each user has a single wallet in USD. Multi-currency wallets would allow merchants to:
- Hold balances in multiple currencies simultaneously
- Receive payments in local currency without automatic conversion
- Choose when to convert currencies (at a favorable rate)
- Pay out to recipients in their local currency from the matching wallet
python# Planned: Multi-currency wallet
class Wallet(Base):
__tablename__ = "wallets"
id = Column(String, primary_key=True)
user_id = Column(String, ForeignKey("users.id"), nullable=False)
currency = Column(String(3), nullable=False)
balance = Column(Float, default=0.0)
reserved = Column(Float, default=0.0) # Held for pending payouts
__table_args__ = (UniqueConstraint("user_id", "currency"),)Marketplace Split Payments
For marketplace platforms where a payment needs to be split between multiple parties:
python# Planned: Split payment API
class SplitPaymentCreate(BaseModel):
amount: float
currency: str
reference: str
splits: list[PaymentSplit]
class PaymentSplit(BaseModel):
recipient_id: str
amount: float # Fixed amount
# OR
percentage: float # Percentage of total
description: str | None = NoneA customer pays $100 for a marketplace purchase. The marketplace takes 15%, the seller gets 85%. The split payment system handles this in a single API call, routing the appropriate amounts to each party.
The Roadmap Timeline
| Quarter | Focus | Key Deliverables |
|---|---|---|
| Q2 2026 | Core extensions | Subscription engine, payout API, dispute management |
| Q3 2026 | Africa depth | M-Pesa deep integration, Airtel Money, Flutterwave |
| Q4 2026 | Platform features | Multi-currency wallets, marketplace splits, AI assistant |
| Q1 2027 | Scale | Advanced analytics, provider health monitoring, anomaly detection |
Each quarter's work will be documented in session logs and eventually in new articles for this series. The build continues.
The Broader Vision
0fee.dev started as a payment orchestrator. The roadmap shows it becoming a financial infrastructure platform. Payments, subscriptions, payouts, wallets, disputes, analytics -- these are the building blocks that every digital business in Africa (and globally) needs.
The vision has not changed since Session 001: one API, one SDK, one dashboard -- and you cover the world. What has changed is our understanding of what "covering the world" really means. It means handling not just one-time payments but every financial operation a business needs. It means not just connecting to providers but actively routing around failures. It means not just processing transactions but providing the intelligence to optimize them.
Eighty-six sessions built the foundation. The next eighty-six will build the future. And they will be built the same way: one CEO, one AI CTO, zero human engineers, from Abidjan.
This article is part of the "How We Built 0fee.dev" series. 0fee.dev is a payment orchestrator covering 53+ providers across 200+ countries, built by Juste A. GNIMAVO and Claude from Abidjan with zero human engineers. Follow the series for the complete build story.