Universal Essentials
Core elements that remain consistent across all frameworks and integration methods.
Universal Constants
These elements never change regardless of which framework or integration method you choose. Understanding these fundamentals will make implementing any framework much easier.
Environment
YagoutPay operates two environments: Test and Production. Credentials are shared upon registration.
Example Environment Configuration with JavaScript:
// Universal Constants (Never Change)
const MERCHANT_ID = '202504290002'; // MERCHANT_ID Shared by yagout team up on registry.
const ENCRYPTION_KEY = 'neTdYIKd87JEj4C6ZoYjaeBiCoeOr40ZKBEI8EU/8lo=';
// Base64 encoded Shared by yagout team up on registry.
const IV = '0123456789abcdef'; // Fixed 16-byte IV
Encryption & Decryption Logic
YagoutPay uses AES-256-CBC encryption with a shared merchant key and a static IV. The encryption algorithm is consistent across all platforms:
Sample JavaScript (Browser) for encryption and decryption:
// JavaScript (Browser - Web Crypto API) - SAME for all frameworks
// Encryption function
async function encryptPaymentData(data) {
const keyBytes = base64ToUint8Array(ENCRYPTION_KEY);
const ivBytes = new TextEncoder().encode(IV);
const cryptoKey = await crypto.subtle.importKey('raw', keyBytes, { name: 'AES-CBC' }, false, ['encrypt']);
const encrypted = await crypto.subtle.encrypt({ name: 'AES-CBC', iv: ivBytes }, cryptoKey, new TextEncoder().encode(JSON.stringify(data)));
return btoa(String.fromCharCode(...new Uint8Array(encrypted)));
}
// Decryption function
async function decryptPaymentData(encryptedData) {
const keyBytes = base64ToUint8Array(ENCRYPTION_KEY);
const ivBytes = new TextEncoder().encode(IV);
const cryptoKey = await crypto.subtle.importKey('raw', keyBytes, { name: 'AES-CBC' }, false, ['decrypt']);
const encryptedBytes = Uint8Array.from(atob(encryptedData), c => c.charCodeAt(0));
const decrypted = await crypto.subtle.decrypt({ name: 'AES-CBC', iv: ivBytes }, cryptoKey, encryptedBytes);
return JSON.parse(new TextDecoder().decode(decrypted));
}
Sample JavaScript (Node.js) for encryption and decryption:
// JavaScript (Node.js - crypto module) - SAME for all frameworks
// Encryption function
function encryptAesCbcBase64(obj) {
const key = Buffer.from(ENCRYPTION_KEY, 'base64');
const iv = Buffer.from(IV, 'utf8');
const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
cipher.setAutoPadding(true);
return Buffer.concat([cipher.update(Buffer.from(JSON.stringify(obj), 'utf8')), cipher.final()]).toString('base64');
}
// Decryption function
function decryptAesCbcBase64(encryptedData) {
const key = Buffer.from(ENCRYPTION_KEY, 'base64');
const iv = Buffer.from(IV, 'utf8');
const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
decipher.setAutoPadding(true);
const decrypted = Buffer.concat([decipher.update(Buffer.from(encryptedData, 'base64')), decipher.final()]);
return JSON.parse(decrypted.toString('utf8'));
}
Customer Information
These fields are mandatory in all integration methods:
Example Customer Data Structure with JavaScript:
// Customer Information (Always Required)
{
customerName: "Customer Name", // or first_name + last_name
emailId: "customer@example.com", // or customer_email
mobileNumber: "0965680964", // or mobile_no
dial_code: "+251" // Always +251 for Ethiopia
}
Transaction Details
These transaction parameters are consistent across all frameworks:
Example Transaction Data Structure with JavaScript:
// Transaction Details (Always Required)
{
meId: "202508080001", // Always the same merchant ID
orderNo: "UNIQUE_ORDER_ID", // Must be unique each time
amount: "1.00", // Always string format
country: "ETH", // Always Ethiopia
currency: "ETB", // Always Ethiopian Birr
transactionType: "SALE" // Always SALE for payments
}
Payment Gateway Details
These gateway settings never change across integration methods:
Example Payment Gateway Configuration with JavaScript:
// Payment Gateway Details (Always Required)
{
pg_Id: "67ee846571e740418d688c3f", // Fixed payment gateway ID
paymode: "WA", // Always WA
scheme_Id: "7", // Always 7
wallet_type: "telebirr" // or "cbe", "awash"
}
URL Structure
Base URLs follow the same pattern, only environment changes:
Example URL Configuration with JavaScript:
// Base URLs (Only Environment Changes)
// UAT (Testing) - Same pattern for all frameworks
const UAT_BASE = 'https://uatcheckout.yagoutpay.com/ms-transaction-core-1-0';
// Production - Same pattern for all frameworks
const PROD_BASE = 'https://checkout.yagoutpay.com/ms-transaction-core-1-0';
// Framework-specific endpoints (only the path changes)
const ENDPOINTS = {
hosted: '/apiRedirection/apiIntegration', // Stage 1
direct: '/apiRedirection/apiIntegration', // Stage 2
paymentLink: '/sdk/paymentByLinkResponse', // Stage 3
staticLink: '/sdk/staticQRPaymentResponse' // Stage 3
};
Request Headers
Header patterns are consistent across all integration methods:
Example Request Headers Configuration with JavaScript:
// Common Headers (Consistent Pattern)
const COMMON_HEADERS = {
'Content-Type': 'application/json',
'Accept': 'application/json, text/plain'
};
// Framework-specific headers
const FRAMEWORK_HEADERS = {
hosted: {}, // Stage 1: Form submission
direct: {}, // Stage 2: No special headers
paymentLink: { 'me_id': MERCHANT_ID }, // Stage 3: me_id header
staticLink: { 'me_id': MERCHANT_ID } // Stage 3: me_id header
};
Response Handling
All frameworks can return these response types:
Example Response Data Structure with JavaScript:
// Response Patterns (Always the Same)
const RESPONSE_TYPES = {
success: {
status: 'Success',
payment_link: 'https://...', // For payment links
transactionId: 'TXN_123'
},
failure: {
status: 'Declined',
statusMessage: 'Order Id already exists'
},
encrypted: {
response: 'BASE64_ENCRYPTED_DATA' // Needs decryption
}
};
Error Handling
These error patterns appear in all frameworks:
Example Error Handling Configuration with JavaScript:
// Universal Error Patterns
const COMMON_ERRORS = {
'Order Id already exists': 'Generate unique order_id',
'Invalid Request Body': 'Check encryption parameters',
'Unexpected token': 'Handle both JSON and plain-text responses',
'INTERNAL_SERVER_ERROR': 'Check headers and body format'
};
Validation Rules
These validation rules apply to all frameworks:
Example Validation Rules Configuration with JavaScript:
// Field Requirements (Never Change)
const VALIDATION_RULES = {
order_id: 'Must be unique, string format',
amount: 'Must be string, minimum 1.00',
mobile_no: 'Required, string format',
country: 'Always "ETH"',
currency: 'Always "ETB"',
dial_code: 'Always "+251"',
expiry_date: 'YYYY-MM-DD format for payment links'
};
What Changes Between Frameworks
Only these elements change:
- API Endpoint URL (different paths)
- Request Body Structure (different wrapper formats)
- Response Processing (different success indicators)
- User Interface (different forms/pages)
Everything Else Stays Identical
- ✅ Encryption algorithm (AES-256-CBC)
- ✅ Key and IV values
- ✅ Customer data structure
- ✅ Transaction details
- ✅ Error handling patterns
- ✅ Validation rules
- ✅ Base URL structure
This is why once you understand the encryption and core data structure for one framework, implementing other frameworks becomes much easier - you're just changing the API endpoint and request wrapper, but the core payment data and encryption remain exactly the same!