Chapter 4: Implementation Guide

In this chapter: Practical step-by-step guide to implementing cross-border payment systems using the WIA-FIN-014 SDK, including code examples, API integration patterns, and development workflows.

4.1 Getting Started

Installation

npm install @wia/cross-border-payment-sdk

Configuration

import { CrossBorderPaymentClient } from '@wia/cross-border-payment-sdk'; const client = new CrossBorderPaymentClient({ apiKey: process.env.WIA_API_KEY, environment: 'production', // or 'sandbox' options: { timeout: 30000, retries: 3, baseURL: 'https://api.wia.org/fin-014/v1' } });

4.2 Creating Your First Payment

Step 1: Get FX Quote

const quote = await client.getQuote({ from: 'USD', to: 'PHP', amount: 1000, method: 'SWIFT' }); console.log('Exchange Rate:', quote.rate); console.log('Recipient Amount:', quote.destinationAmount); console.log('Fees:', quote.fees); console.log('Total Cost:', quote.totalCost);

Step 2: Verify Beneficiary

const beneficiary = await client.createBeneficiary({ name: 'Jane Smith', country: 'PH', currency: 'PHP', accountNumber: '1234567890', bankCode: 'BDO', accountType: 'SAVINGS', address: { street: '123 Makati Ave', city: 'Manila', postalCode: '1200', country: 'PH' } }); console.log('Beneficiary ID:', beneficiary.id);

Step 3: Initiate Payment

const payment = await client.createPayment({ beneficiaryId: beneficiary.id, amount: 1000, currency: 'USD', purpose: 'Family support', reference: 'INV-2025-001', method: 'SWIFT', metadata: { invoiceId: 'INV-2025-001', customerEmail: 'john.doe@example.com' } }); console.log('Payment ID:', payment.id); console.log('Status:', payment.status); console.log('Estimated Delivery:', payment.estimatedDelivery);

4.3 Payment Status Tracking

Polling Method

async function waitForCompletion(paymentId: string) { let status = 'PENDING'; while (status !== 'COMPLETED' && status !== 'FAILED') { const payment = await client.getPayment(paymentId); status = payment.status; console.log(`Status: ${status}`); if (status === 'COMPLETED') { console.log('Payment completed successfully!'); console.log('Transaction Reference:', payment.transactionReference); return payment; } if (status === 'FAILED') { console.error('Payment failed:', payment.failureReason); throw new Error(payment.failureReason); } await sleep(5000); // Wait 5 seconds before next poll } }

Webhook Method (Recommended)

// Express.js webhook endpoint app.post('/webhooks/payment', async (req, res) => { const signature = req.headers['x-wia-signature']; // Verify webhook signature const isValid = client.verifyWebhookSignature( req.body, signature, process.env.WEBHOOK_SECRET ); if (!isValid) { return res.status(401).send('Invalid signature'); } const event = req.body; switch (event.type) { case 'payment.created': console.log('Payment created:', event.data.id); break; case 'payment.processing': console.log('Payment processing:', event.data.id); break; case 'payment.completed': console.log('Payment completed:', event.data.id); await updateDatabase(event.data); await sendConfirmationEmail(event.data); break; case 'payment.failed': console.error('Payment failed:', event.data.failureReason); await notifyCustomer(event.data); break; } res.sendStatus(200); });

4.4 Advanced Features

Batch Payments

const batch = await client.createBatchPayment({ payments: [ { beneficiaryId: 'BEN-001', amount: 500, currency: 'USD', purpose: 'Salary payment' }, { beneficiaryId: 'BEN-002', amount: 750, currency: 'USD', purpose: 'Supplier payment' }, { beneficiaryId: 'BEN-003', amount: 1000, currency: 'USD', purpose: 'Contractor payment' } ], method: 'SWIFT', scheduledDate: '2025-12-30' }); console.log('Batch ID:', batch.id); console.log('Total Amount:', batch.totalAmount); console.log('Payment Count:', batch.paymentCount);

FX Rate Locking

// Lock rate for 24 hours const rateLock = await client.lockFxRate({ from: 'USD', to: 'EUR', amount: 10000, duration: 86400 // 24 hours in seconds }); console.log('Locked Rate:', rateLock.rate); console.log('Expires At:', rateLock.expiresAt); // Use locked rate for payment const payment = await client.createPayment({ beneficiaryId: 'BEN-123', amount: 10000, currency: 'USD', rateLockId: rateLock.id });

Compliance Pre-Check

const complianceCheck = await client.checkCompliance({ sender: { name: 'John Doe', country: 'US', idType: 'PASSPORT', idNumber: 'AB1234567' }, recipient: { name: 'Jane Smith', country: 'PH' }, amount: 10000, currency: 'USD' }); if (complianceCheck.approved) { console.log('Compliance check passed'); } else { console.log('Additional verification required'); console.log('Reasons:', complianceCheck.reasons); }

4.5 Error Handling

try { const payment = await client.createPayment(paymentData); } catch (error) { if (error instanceof WiaApiError) { switch (error.code) { case 'INSUFFICIENT_BALANCE': console.log('Insufficient balance in account'); break; case 'INVALID_BENEFICIARY': console.log('Beneficiary details invalid'); break; case 'COMPLIANCE_FAILED': console.log('Compliance check failed'); console.log('Reason:', error.message); break; case 'RATE_LIMIT_EXCEEDED': console.log('Too many requests, retry later'); await sleep(error.retryAfter * 1000); break; default: console.error('Payment error:', error.message); } } else { console.error('Unexpected error:', error); } }

4.6 Testing

Sandbox Environment

// Use sandbox for testing const testClient = new CrossBorderPaymentClient({ apiKey: process.env.WIA_SANDBOX_KEY, environment: 'sandbox' }); // Sandbox test cards and accounts const testBeneficiary = await testClient.createBeneficiary({ name: 'Test Beneficiary', country: 'PH', accountNumber: 'TEST-1234567890', // Sandbox test account bankCode: 'BDO' });

Unit Tests Example

import { describe, it, expect } from 'vitest'; import { CrossBorderPaymentClient } from '@wia/cross-border-payment-sdk'; describe('Cross-Border Payment', () => { const client = new CrossBorderPaymentClient({ apiKey: 'test-key', environment: 'sandbox' }); it('should create payment successfully', async () => { const payment = await client.createPayment({ beneficiaryId: 'TEST-BEN-001', amount: 100, currency: 'USD', purpose: 'Test payment' }); expect(payment.id).toBeDefined(); expect(payment.status).toBe('PENDING'); }); it('should handle invalid beneficiary', async () => { await expect( client.createPayment({ beneficiaryId: 'INVALID', amount: 100, currency: 'USD' }) ).rejects.toThrow('Invalid beneficiary'); }); });

💡 Best Practices: