Build a Remittance App with MoneyGraph
Complete guide to building an international money transfer app. Includes sender onboarding, KYC, recipient management, FX quotes, and multi-rail payouts.
# Build a Remittance App with MoneyGraph
This recipe shows you how to build a complete international remittance application using MoneyGraph SDK. Send money across 107+ countries via multiple payment rails: local bank transfers, SWIFT, mobile money (M-Pesa, MTN), and cryptocurrency.
User Journey Overview
┌─────────────────────────────────────────────────────────────────────────────┐
│ REMITTANCE APP USER JOURNEY │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ 1. SENDER REGISTRATION │
│ ├── User signs up with basic info │
│ └── Create customer: mg.customers.create() │
│ │
│ 2. SENDER KYC (REQUIRED BEFORE ANY PAYOUT) │
│ ├── Update customer with KYC details │
│ ├── Upload documents: mg.customers.kyc.uploadDocument() │
│ ├── Submit KYC: mg.customers.kyc.submit() │
│ └── Wait for approval │
│ │
│ 3. SELECT DESTINATION │
│ ├── Choose country: mg.reference.countries() │
│ └── Get banks: mg.reference.banks.list() │
│ │
│ 4. GET FX QUOTE │
│ ├── Request quote: mg.fx.quote({ from, to, amount }) │
│ ├── Display: rate, fees, recipient amount │
│ └── Quote valid for 2 MINUTES │
│ │
│ 5. EXECUTE PAYOUT │
│ ├── Verify KYC: mg.customers.kyc.canPayout() │
│ ├── Confirm rate: mg.fx.confirm(quote.id) │
│ └── Send money: mg.executeSmartPayout() │
│ │
│ 6. TRACK STATUS │
│ ├── Get status: mg.payouts.retrieve() │
│ └── Webhooks for real-time updates │
│ │
└─────────────────────────────────────────────────────────────────────────────┘AI Agent Quick Start
Use this prompt with your AI coding assistant:
Build a remittance/money transfer app using MoneyGraph SDK with these features:- USER REGISTRATION
- - Signup form: name, email, phone, country
- - Create sender: mg.customers.create({ account_type: 'personal', ... })
- KYC VERIFICATION (REQUIRED BEFORE ANY TRANSFERS)
- - KYC form: birthday (DD-MM-YYYY!), ID type, ID number, address
- - Update customer: mg.customers.update()
- - Upload documents: mg.customers.kyc.uploadDocument()
- - id_front, id_back (optional), selfie
- - Submit: mg.customers.kyc.submit({ id_type, id_number })
- - Check status: mg.customers.kyc.getStatus()
- - BLOCK transfers until status === 'APPROVED'
- SEND MONEY FLOW
- a. Select destination country and currency
- - Get countries: mg.reference.countries()
- - Get banks: mg.reference.banks.list(countryIso2)
b. Add recipient (based on delivery method): - Bank: name, bank_code, account_number - Mobile Money: name, mobile_network (MPESA/MTN), mobile_number - SWIFT: name, swift_code, iban, bank_name - Crypto: name, wallet_address, network (ETH/TRON)
c. Get quote (show countdown - 2 minute expiry!) - mg.fx.quote({ from, to, amount }) - Display: rate, fee, recipient amount
d. Confirm and send - Check KYC: mg.customers.kyc.canPayout() - RECOMMENDED: mg.executeSmartPayout() for automatic routing - Or use specific rail: mg.payouts.create(), mg.payouts.mobileMoney.create()
- TRANSACTION TRACKING
- - List history: mg.payouts.list({ customer_id })
- - Get status: mg.payouts.retrieve(payoutId)
- - Status flow: pending → processing → completed/failed
SUPPORTED PAYMENT RAILS: - mg.payouts.create() - Local bank transfers (107 countries) - mg.payouts.mobileMoney.create() - M-Pesa, MTN, Airtel (30+ networks) - mg.payouts.swift.create() - International wire (190 corridors) - mg.payouts.crypto.create() - USDC, USDT, ETH, BTC
CRITICAL RULES: - NEVER allow payouts without approved KYC - ALWAYS call mg.fx.confirm() before mg.payouts.create() - Quote expires in 2 MINUTES - show countdown - Birthday format MUST be DD-MM-YYYY - Use mg.executeSmartPayout() for simplest integration
SANDBOX TESTING: - Use mg.customers.createMockPersona('individual_verified') for instant verified sender ```
Complete Implementation
Step 1: Sender Registration
import { MoneyGraph } from '@moneygraph/sdk';const mg = new MoneyGraph({ apiKey: process.env.MONEYGRAPH_API_KEY! });
export async function registerSender(data: { firstName: string; lastName: string; email: string; phone: string; country: string; }) { const customer = await mg.customers.create({ account_type: 'personal', first_name: data.firstName, last_name: data.lastName, email: data.email, phone: data.phone.replace(/\D/g, ''), phone_iso2: data.country, country: data.country, });
return { customerId: customer.id }; } ```
Step 2: Complete KYC
export async function submitKYC(customerId: string, data: {
birthday: string; // DD-MM-YYYY
idType: 'PASSPORT' | 'DRIVERS' | 'NATIONAL_ID';
idNumber: string;
}) {
// Update customer with details
await mg.customers.update(customerId, {
birthday: data.birthday,
});// Submit KYC await mg.customers.kyc.submit(customerId, { id_type: data.idType, id_number: data.idNumber, });
return { status: 'pending' }; } ```
Step 3: Get FX Quote
export async function getQuote(params: {
fromCurrency: string;
toCurrency: string;
amount: number;
}) {
const quote = await mg.fx.quote({
from: params.fromCurrency as any,
to: params.toCurrency as any,
amount: params.amount,
});return { quoteId: quote.id, rate: quote.rate, fromAmount: quote.from_amount, toAmount: quote.to_amount, fee: quote.fee, expiresAt: quote.expires_at, }; } ```
Step 4: Send Money (Smart Payout)
export async function sendMoney(params: {
customerId: string;
fromCurrency: string;
toCurrency: string;
amount: number;
recipient: {
name: string;
bankCode?: string;
accountNumber?: string;
mobileNetwork?: string;
mobileNumber?: string;
};
}) {
// Verify KYC first!
const eligibility = await mg.customers.kyc.canPayout(params.customerId);
if (!eligibility.can_payout) {
return {
success: false,
error: 'Complete KYC verification first'
};
}// Execute smart payout (handles all rails automatically) const result = await mg.executeSmartPayout({ customer_id: params.customerId, from_currency: params.fromCurrency as any, to_currency: params.toCurrency as any, amount: params.amount, recipient: params.recipient, priority: 'cost', });
return result; } ```
Step 5: Track Status
export async function getPayoutStatus(payoutId: string) {
const payout = await mg.payouts.retrieve(payoutId);return { id: payout.id, status: payout.status, amount: payout.amount, currency: payout.currency, recipient: payout.recipient, }; } ```
Payment Rails Support
| Rail | Method | Use Case |
|---|---|---|
| Local Bank | mg.payouts.create() | Nigeria, Kenya, Ghana, etc. |
| Mobile Money | mg.payouts.mobileMoney.create() | M-Pesa, MTN, Airtel |
| SWIFT | mg.payouts.swift.create() | International wire |
| Crypto | mg.payouts.crypto.create() | USDC, USDT, ETH |
| Smart | mg.executeSmartPayout() | Auto-selects best rail |
Next Steps
Resources:
- MoneyGraph SDK Documentation - Complete API reference
- FX Quotes Guide - Rate locking explained
- Multi-Rail Payouts - All delivery methods
Ready to Build?
Install MoneyGraph SDK and start building with AI assistance