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.
npm install @wia/cross-border-payment-sdkimport { 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'
}
});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);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);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);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
}
}// 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);
});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);// 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
});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);
}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);
}
}// 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'
});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: