A production-ready backend service that bridges African mobile money providers (MTN, Airtel, Orange) with the Stellar blockchain network, enabling seamless cross-border payments and remittances.
This platform solves a critical problem in African financial infrastructure: connecting traditional mobile money systems with blockchain technology. We enable:
- Cross-border remittances with lower fees than traditional services
- Instant settlements using Stellar's fast blockchain
- Financial inclusion by bridging mobile money (used by 500M+ Africans) with global crypto markets
- Compliance-first approach with built-in KYC, AML monitoring, and transaction limits
- Developer-friendly APIs (REST + GraphQL) for easy integration
- Remittances: Send money from Europe/US to Africa instantly via Stellar, recipient withdraws to mobile money
- Cross-border payments: Pay suppliers in different African countries without expensive wire transfers
- Savings in stable assets: Convert volatile local currency to USDC/XLM via mobile money
- Merchant payments: Accept crypto payments, settle in local mobile money
- DeFi access: Bridge between mobile money and Stellar DeFi protocols
- Mobile Money Integration: MTN, Airtel, Orange Money support
- Stellar Blockchain: Native XLM and custom asset support (USDC, anchored assets)
- Dual API: RESTful API + GraphQL for flexible integration
- Real-time Processing: Background job queues with BullMQ and Redis
- WebSocket Support: Live transaction updates and notifications
- KYC/AML: Multi-tier verification with transaction limits
- 2FA: TOTP-based two-factor authentication
- RBAC: Role-based access control with Casbin
- Rate Limiting: Intelligent rate limiting and DDoS protection
- Audit Logging: Comprehensive audit trails for compliance
- Session Security: IP tracking, device fingerprinting, anomaly detection
- Dynamic Fees: VIP tiers with volume-based discounts
- Transaction Limits: Provider-specific and KYC-based limits
- Vault System: Secure fund storage and management
- Accounting Integration: QuickBooks and Xero sync
- Dispute Management: Full dispute workflow and resolution
- Fee Bumping: Automatic Stellar transaction fee adjustment
- TypeScript: Full type safety and IntelliSense
- Docker Support: Development and production containers
- Database Migrations: Automated schema management
- Comprehensive Testing: Unit, integration, E2E, and load tests
- CI/CD: GitHub Actions with automated testing and deployment
- API Documentation: OpenAPI/Swagger specs
- Webhook Support: Zapier/Make.com integration
- SEP-10: Stellar Web Authentication
- SEP-12: KYC API
- SEP-24: Hosted Deposit and Withdrawal
- SEP-31: Cross-Border Payments
- SEP-38: Quotes and Price Streams
- Node.js 20+ (LTS recommended)
- PostgreSQL 16+
- Redis 7+
- Docker (optional, for containerized development)
git clone https://github.com/sublime247/mobile-money.git
cd mobile-moneynpm installcp .env.example .envEdit .env with your configuration:
# Database
DATABASE_URL=postgresql://user:password@localhost:5432/mobilemoney
# Redis
REDIS_URL=redis://localhost:6379
# Stellar Network
STELLAR_NETWORK=testnet # or 'mainnet'
STELLAR_HORIZON_URL=https://horizon-testnet.stellar.org
STELLAR_ISSUER_SECRET=S... # Your Stellar secret key
# Mobile Money Providers
MTN_API_KEY=your_mtn_api_key
MTN_API_SECRET=your_mtn_secret
AIRTEL_API_KEY=your_airtel_key
ORANGE_API_KEY=your_orange_key
# Security
JWT_SECRET=your_jwt_secret_min_32_chars
SESSION_SECRET=your_session_secret
# Optional: Email notifications
SENDGRID_API_KEY=your_sendgrid_key
FROM_EMAIL=noreply@yourdomain.com
# Optional: SMS notifications
TWILIO_ACCOUNT_SID=your_twilio_sid
TWILIO_AUTH_TOKEN=your_twilio_token
TWILIO_PHONE_NUMBER=+1234567890# Run migrations
npm run migrate:up
# Seed development data (optional)
NODE_ENV=development npm run seednpm run devServer starts at http://localhost:3000
npm run build
npm start# Start all services (app, PostgreSQL, Redis)
npm run docker:dev
# Stop services
npm run docker:dev:downIncludes hot reload and debugger on port 9229.
The development compose stack now also starts a local provider mock server on
http://localhost:4010 and points MTN/Airtel traffic at it automatically.
Use ?scenario=success|failed|pending or x-mock-scenario to control mock
responses, and ?delayMs=... or x-mock-delay-ms to simulate timeouts.
To run only the mock server outside Docker:
npm run provider-mock:devdocker-compose up -dnpm testnpm run test:coverageMinimum coverage requirements: 70% (branches, functions, lines, statements)
npm run test:watchnpm run test:e2e# Basic load test
npm run test:load
# Stress test
npm run test:load:stress
# Transaction-focused test
npm run test:load:transactionsnpm run test:mutationThe API spec is generated at runtime directly from the Zod validation schemas β there is no manually maintained YAML or JSON file to keep in sync.
Accessing the docs locally
-
Start the server in development mode:
npm run dev
-
Open your browser at:
http://localhost:3000/docsSwagger UI loads with the full spec, including request/response shapes, examples, and a "Try it out" button for every endpoint.
-
The raw OpenAPI 3.0 JSON is also available at:
http://localhost:3000/docs/openapi.json
Docs are not available in production β both /docs and /docs/openapi.json return 404 when NODE_ENV !== 'development'.
The source of truth is src/openapi/schemas/, not openapi.yaml.
| File / folder | Purpose |
|---|---|
src/openapi/registry.ts |
Calls extendZodWithOpenApi(z) once; exports the shared registry |
src/openapi/schemas/*.ts |
One file per domain β Zod schemas annotated with .openapi({ description, example }) |
src/openapi/paths/*.ts |
Route registrations (registry.registerPath(...)) per domain |
src/openapi/generator.ts |
Assembles the spec via OpenApiGeneratorV3 on every server start |
src/routes/docs.ts |
Mounts Swagger UI and the JSON endpoint, dev-only |
To update the docs: edit or add a schema in src/openapi/schemas/, then restart the server (npm run dev uses tsx watch so it restarts automatically). The change appears in /docs immediately β no manual sync step.
openapi.yamlin the repo root is a legacy file kept only for the SDK generator script (npm run sdk:generate). It is no longer the source of truth and will be removed in a future cleanup.Backlog: point
sdk:generateathttp://localhost:3000/docs/openapi.jsoninstead ofopenapi.yaml. The dev server would need to be running during SDK generation, but it would mean the SDK always reflects the live Zod schemas with no manual sync. Once that's done,openapi.yamlcan be deleted entirely.
http://localhost:3000/api
Most endpoints require authentication via JWT token:
Authorization: Bearer <your_jwt_token>Or API key for admin operations:
X-API-Key: <your_api_key>GET /health # Service health status
GET /ready # Readiness probe (checks DB and Redis)POST /api/transactions/deposit # Deposit from mobile money to Stellar
POST /api/transactions/withdraw # Withdraw from Stellar to mobile money
GET /api/transactions # List transactions (paginated)
GET /api/transactions/:id # Get transaction details
POST /api/transactions/:id/cancel # Cancel pending transaction
POST /api/transactions/:id/dispute # Create disputePOST /api/auth/register # Register new user
POST /api/auth/login # Login
POST /api/auth/logout # Logout
POST /api/auth/2fa/enable # Enable 2FA
POST /api/auth/2fa/verify # Verify 2FA code
GET /api/users/profile # Get user profile
PUT /api/users/profile # Update profilePOST /api/kyc/submit # Submit KYC documents
GET /api/kyc/status # Check KYC status
POST /api/kyc/upload # Upload documentPOST /api/vaults # Create vault
GET /api/vaults # List user vaults
GET /api/vaults/:id # Get vault details
POST /api/vaults/:id/transfer # Deposit/withdraw from vaultGET /api/admin/users # List all users
GET /api/admin/transactions # All transactions
POST /api/admin/fees/configurations # Create fee config
GET /api/stats # System statisticsPOST /graphqlGraphQL Playground available at http://localhost:3000/graphql in development.
Example query:
query {
transactions(limit: 10) {
id
amount
status
provider
createdAt
}
}
mutation {
createDeposit(input: {
amount: "10000"
phoneNumber: "+237670000000"
provider: MTN
}) {
id
status
referenceNumber
}
}Configure webhooks to receive real-time notifications:
POST /api/webhooks # Create webhook
GET /api/webhooks # List webhooks
DELETE /api/webhooks/:id # Delete webhookSupported events:
transaction.completedtransaction.failedtransaction.pendingkyc.approvedkyc.rejected
| Limit | Amount | Purpose |
|---|---|---|
| Minimum | 100 XAF | Prevent spam |
| Maximum | 1,000,000 XAF | Fraud prevention |
| KYC Level | Daily Limit | Requirements |
|---|---|---|
| Unverified | 10,000 XAF | Email verification only |
| Basic | 100,000 XAF | ID document + selfie |
| Full | 1,000,000 XAF | Proof of address + video verification |
| Provider | Min | Max | Notes |
|---|---|---|---|
| MTN | 100 XAF | 500,000 XAF | Most common |
| Airtel | 100 XAF | 1,000,000 XAF | Higher limits |
| Orange | 500 XAF | 750,000 XAF | Higher minimum |
Automatic flagging of suspicious transactions:
- Single transaction > 1,000,000 XAF
- 24-hour total > 5,000,000 XAF
- Rapid structuring (3+ mixed transactions in 15 minutes)
- Export endpoints: 5 requests/hour
- API endpoints: Configurable per endpoint
- GraphQL: Query complexity limits
Backend
- Node.js + TypeScript
- Express.js (REST API)
- Apollo Server (GraphQL)
- PostgreSQL (primary database)
- Redis (caching, sessions, queues)
Blockchain
- Stellar SDK
- Horizon API integration
- Custom asset support
Background Jobs
- BullMQ (job queues)
- Node-cron (scheduled tasks)
Security
- Helmet (HTTP headers)
- Bcrypt (password hashing)
- JWT (authentication)
- Speakeasy (2FA)
- Casbin (RBAC)
Monitoring
- Datadog APM
- Sentry (error tracking)
- Prometheus metrics
- Custom health checks
mobile-money/
βββ src/
β βββ auth/ # Authentication & authorization
β βββ config/ # Configuration files
β βββ controllers/ # Request handlers
β βββ crypto/ # HSM and encryption
β βββ graphql/ # GraphQL schema & resolvers
β βββ jobs/ # Background jobs
β βββ middleware/ # Express middleware
β βββ models/ # Database models
β βββ queue/ # Job queue management
β βββ routes/ # API routes
β βββ scripts/ # Utility scripts
β βββ services/ # Business logic
β β βββ mobilemoney/ # Mobile money integrations
β β βββ stellar/ # Stellar blockchain services
β βββ stellar/ # Stellar SEP implementations
β βββ types/ # TypeScript type definitions
β βββ utils/ # Helper functions
β βββ websocket/ # WebSocket server
β βββ index.ts # Application entry point
βββ tests/ # Test files
β βββ e2e/ # End-to-end tests
β βββ integration/ # Integration tests
β βββ load/ # Load tests
β βββ unit/ # Unit tests
βββ migrations/ # Database migrations
βββ contracts/ # Stellar smart contracts
βββ .github/ # GitHub Actions workflows
βββ docker/ # Docker configurations
npm run migrate:create -- migration_namenpm run migrate:upnpm run migrate:downnpm run migrate:statusWe welcome contributions! Please see our Contributing Guidelines.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Run tests (
npm test) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Pre-commit hooks automatically run:
- ESLint (linting)
- Prettier (formatting)
- TypeScript type checking
- Tests
Bypass hooks (not recommended):
git commit --no-verifyCheck out issues labeled good first issue for beginner-friendly tasks.
Prometheus metrics available at /metrics:
- Transaction counts by status
- API response times
- Queue depths
- Error rates
- Provider availability
# Liveness probe
curl http://localhost:3000/health
# Readiness probe (checks dependencies)
curl http://localhost:3000/readyStructured JSON logging with levels:
error: Critical errorswarn: Warnings and anomaliesinfo: General informationdebug: Detailed debugging (dev only)
Sentry integration for production error monitoring:
SENTRY_DSN=your_sentry_dsnRequired for production:
NODE_ENV=production
DATABASE_URL=postgresql://...
REDIS_URL=redis://...
STELLAR_NETWORK=mainnet
STELLAR_ISSUER_SECRET=S...
JWT_SECRET=...
SESSION_SECRET=...docker build -t mobile-money:latest .
docker run -p 3000:3000 --env-file .env mobile-money:latestExample deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: mobile-money
spec:
replicas: 3
selector:
matchLabels:
app: mobile-money
template:
metadata:
labels:
app: mobile-money
spec:
containers:
- name: mobile-money
image: mobile-money:latest
ports:
- containerPort: 3000
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: mobile-money-secrets
key: database-url
livenessProbe:
httpGet:
path: /health
port: 3000
readinessProbe:
httpGet:
path: /ready
port: 3000- API Response Time: < 100ms (p95)
- Transaction Processing: < 5s (end-to-end)
- Throughput: 1000+ req/s
- Database Queries: < 50ms (p95)
- Enable Redis caching
- Use connection pooling
- Implement CDN for static assets
- Enable compression middleware
- Use database indexes
- Implement query result caching
Database connection fails
# Check PostgreSQL is running
pg_isready -h localhost -p 5432
# Verify DATABASE_URL format
postgresql://user:password@host:port/databaseRedis connection fails
# Check Redis is running
redis-cli ping
# Should return: PONGStellar transactions fail
# Verify network configuration
echo $STELLAR_NETWORK # Should be 'testnet' or 'mainnet'
# Check Horizon connectivity
curl https://horizon-testnet.stellar.orgTests failing
# Clear test database
npm run migrate:down
npm run migrate:up
# Clear Jest cache
npm test -- --clearCacheThe Mobile Money Bridge uses standardized error codes for consistent error handling across the API. All errors follow a consistent format with specific error codes that map to appropriate HTTP status codes.
Error codes are string constants organized by category:
- Validation errors (4000-4099) - HTTP 400 (e.g., INVALID_INPUT, MISSING_FIELD)
- Authentication errors (4010-4019) - HTTP 401 (e.g., UNAUTHORIZED, INVALID_CREDENTIALS)
- Authorization errors (4030-4039) - HTTP 403 (e.g., FORBIDDEN, INSUFFICIENT_PERMISSIONS)
- Resource errors (4040-4049) - HTTP 404 (e.g., NOT_FOUND, TRANSACTION_NOT_FOUND)
- Conflict errors (4090-4099) - HTTP 409 (e.g., CONFLICT, DUPLICATE_REQUEST)
- Rate limit errors (4290-4299) - HTTP 429 (e.g., RATE_LIMIT, ACCOUNT_LOCKED)
- Server errors (5000+) - HTTP 500+ (e.g., INTERNAL_ERROR, DATABASE_ERROR)
import { ERROR_CODES } from './constants/errorCodes';
// Throw an error with a specific code
throw createError(ERROR_CODES.INVALID_INPUT);
// The error handler will automatically map to the correct HTTP status
// INVALID_INPUT maps to HTTP 400 Bad RequestSee src/constants/errorCodes.ts for the complete list of error codes and their descriptions.
The getHttpStatus function maps error codes to HTTP status codes:
- 400 Bad Request: Validation/input errors
- 401 Unauthorized: Authentication errors
- 403 Forbidden: Authorization/permission errors
- 404 Not Found: Resource not found errors
- 409 Conflict: State/conflict errors
- 429 Too Many Requests: Rate limit/quota exceeded
- 500 Internal Server Error: Server/database errors
- 502 Bad Gateway: External provider errors
This project is licensed under the MIT License - see the LICENSE file for details.
- Stellar Development Foundation for blockchain infrastructure
- Mobile money providers (MTN, Airtel, Orange) for API access
- Open source community for amazing tools and libraries
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Additional mobile money providers (Vodacom, Tigo)
- Mobile SDKs (iOS, Android)
- Merchant dashboard
- Advanced analytics
- Multi-currency support
- Stablecoin integration (USDC, USDT)
- DeFi protocol integrations
- Automated market making
Built with β€οΈ for financial inclusion in Africa
This repository now includes a dedicated documentation portal in docs-portal/ that transforms openapi.yaml into a searchable, partner-friendly API reference.
npm run docs:devnpm run docs:buildOn every GitHub Release publication, the workflow .github/workflows/api-docs-portal.yml builds docs-portal and deploys it to GitHub Pages.