CI/CD
This guide covers best practices for integrating lomi. with your CI/CD pipeline, ensuring reliable deployments and automated testing.
Environment setup
Environment variables
# .env.ci
LOMI_API_KEY=lomi_sk_test_... # Use a dedicated test key
LOMI_WEBHOOK_SECRET=whsec_... # Test webhook secret
LOMI_API_URL=https://sandbox.api.lomi.africa # Point to sandbox
LOMI_ENV=testSecrets management
Ensure your CI/CD environment securely loads required secrets. Never commit secrets directly to your repository.
// config/secrets.ts
export function loadSecrets(): void {
const requiredSecrets = ['LOMI_API_KEY', 'LOMI_WEBHOOK_SECRET'];
for (const secret of requiredSecrets) {
if (!process.env[secret]) {
console.warn(`Warning: Missing recommended secret: ${secret}`);
// Depending on your setup, you might throw an error:
// throw new Error(`Missing required secret: ${secret}`);
}
}
}
// Call loadSecrets() early in your application or test setupGitHub Actions
Test workflow
Run your integration tests against the lomi. sandbox environment on pushes and pull requests.
name: Test
on:
push:
branches: [main, develop] # Trigger on main and develop branches
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3 # Use latest version
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18' # Use a current LTS version
cache: 'npm' # Cache npm dependencies
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
env:
LOMI_API_KEY: ${{ secrets.LOMI_TEST_API_KEY }} # Use GitHub secrets
LOMI_WEBHOOK_SECRET: ${{ secrets.LOMI_TEST_WEBHOOK_SECRET }}
LOMI_API_URL: 'https://sandbox.api.lomi.africa'
LOMI_ENV: testDeploy workflow
Deploy your application using live keys only when pushing to your main branch.
name: Deploy
on:
push:
branches: [main] # Only trigger on pushes to main
jobs:
deploy:
runs-on: ubuntu-latest
environment: production # Optional: Define a GitHub environment for protection rules
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
# Example: Deploy to AWS (replace with your deployment provider)
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: eu-west-1 # Your region
- name: Install, Build, and Deploy
run: |
npm ci
npm run build
npm run deploy # Your deployment script
env:
LOMI_API_KEY: ${{ secrets.LOMI_PROD_API_KEY }}
LOMI_WEBHOOK_SECRET: ${{ secrets.LOMI_PROD_WEBHOOK_SECRET }}
LOMI_API_URL: 'https://api.lomi.africa'
LOMI_ENV: productionAutomated testing
Pre-deployment checks
Before deploying, run checks to ensure basic connectivity and configuration.
// scripts/pre-deploy-check.ts
import { LomiSDK } from '@lomi./sdk'; // Assuming your SDK package name
async function runPreDeploymentChecks(): Promise<void> {
console.log('Running pre-deployment checks...');
const apiKey = process.env.LOMI_API_KEY;
const apiUrl = process.env.LOMI_API_URL;
if (!apiKey || !apiUrl) {
throw new Error('LOMI_API_KEY and LOMI_API_URL must be set');
}
const lomi = new LomiSDK({
apiKey: apiKey,
baseUrl: apiUrl,
});
try {
// 1. Verify API connectivity (e.g., fetch providers)
console.log('Checking API connectivity...');
const providers = await lomi.providers.listProviders();
if (!providers || providers.data.length === 0) {
throw new Error('Failed to fetch providers or no providers available.');
}
console.log(`Successfully fetched ${providers.data.length} providers.`);
// 2. Optional: Test webhook endpoint connectivity if applicable
// Note: The SDK might not have a direct webhook test method.
// You might need a custom check or rely on integration tests.
// Example placeholder:
// console.log('Checking webhook endpoint...');
// const webhookTestResult = await checkMyWebhookEndpoint();
// if (!webhookTestResult.success) throw new Error('Webhook endpoint check failed');
console.log('Pre-deployment checks passed!');
} catch (error) {
console.error('Pre-deployment check failed:', error);
process.exit(1); // Exit with error code
}
}
runPreDeploymentChecks();Integration tests
Write tests that simulate user flows involving lomi. interactions.
// tests/integration/payment.test.ts
import { LomiSDK } from '@lomi./sdk';
// Assume setup/teardown logic exists elsewhere
describe('Payment Integration', () => {
let lomi: LomiSDK;
beforeAll(() => {
// Ensure required env vars are set for tests
if (!process.env.LOMI_TEST_API_KEY || !process.env.TEST_MERCHANT_ID) {
throw new Error('Missing test environment variables');
}
lomi = new LomiSDK({
apiKey: process.env.LOMI_TEST_API_KEY,
baseUrl: 'https://sandbox.api.lomi.africa',
});
// await setupTestEnvironment(); // Your test setup
});
it('should process a test payment end-to-end', async () => {
// Create checkout session
const sessionResponse = await lomi.checkoutSessions.create({
merchant_id: process.env.TEST_MERCHANT_ID!, // Use a test merchant ID
amount: 1000, // Min amount for testing
currency_code: 'XOF',
success_url: 'https://example.com/success',
cancel_url: 'https://example.com/cancel',
metadata: { test_order_id: `e2e_${Date.now()}` },
});
const sessionId = sessionResponse.data.checkout_session_id;
expect(sessionId).toBeDefined();
// Simulate payment (requires a test helper or specific endpoint)
// This part is highly dependent on lomi.'s testing capabilities
// await lomi.testing.simulatePayment(sessionId, 'succeeded');
// Verify success (allow time for processing)
// await new Promise(r => setTimeout(r, 5000)); // Wait if needed
// const updatedSession = await lomi.checkoutSessions.get(sessionId);
// expect(updatedSession.data.status).toBe('completed');
}, 30000); // Increase timeout for E2E test
});Deployment strategies
Choose a strategy that minimizes risk during deployment.
Blue-green deployment
Maintain two identical production environments (Blue and Green). Deploy to the inactive environment, test, then switch traffic.
// scripts/deploy-blue-green.ts
async function blueGreenDeploy(newVersion: string): Promise<void> {
const currentActive = await getActiveEnvironment(); // e.g., 'blue'
const inactiveEnv = currentActive === 'blue' ? 'green' : 'blue';
// 1. Deploy to inactive environment
console.log(`Deploying version ${newVersion} to ${inactiveEnv}...`);
await deployToEnvironment(inactiveEnv, newVersion);
// 2. Run health checks on inactive environment
console.log(`Running health checks on ${inactiveEnv}...`);
const health = await checkHealth(inactiveEnv);
if (!health.ok) {
console.error(
`Health check failed for ${inactiveEnv}. Rolling back deployment.`,
);
// await rollbackDeployment(inactiveEnv); // Optional rollback
throw new Error('Health check failed on inactive environment');
}
// 3. Switch traffic
console.log(`Switching traffic to ${inactiveEnv}...`);
await switchTraffic(inactiveEnv);
// 4. Monitor the new active environment
console.log(`Monitoring ${inactiveEnv}...`);
// await monitorDeployment(inactiveEnv);
// 5. Optional: Tear down the old environment after a period
}Canary deployment
Gradually roll out the new version to a small subset of users/traffic before releasing it fully.
// scripts/deploy-canary.ts
async function canaryDeploy(newVersion: string): Promise<void> {
// 1. Deploy new version alongside current version with limited traffic (e.g., 10%)
console.log(`Deploying canary version ${newVersion} with 10% traffic...`);
await deployCanaryVersion(newVersion, '10%');
// 2. Monitor metrics (error rates, latency) for a defined period
console.log('Monitoring canary metrics...');
const metricsOk = await monitorCanaryMetrics({
duration: '1h',
errorThreshold: 0.05,
});
if (!metricsOk) {
console.error('Canary metrics failed. Rolling back canary...');
await rollbackCanary(newVersion);
throw new Error('Canary deployment failed metrics check');
}
// 3. Gradually increase traffic to the new version
console.log('Canary metrics OK. Gradually increasing traffic...');
await scaleCanaryTraffic(newVersion, '50%');
await monitorCanaryMetrics({ duration: '30m' }); // Monitor again
await scaleCanaryTraffic(newVersion, '100%'); // Full rollout
// 4. Decommission the old version
console.log('Canary deployment successful. Decommissioning old version...');
await decommissionOldVersion();
}Monitoring
Continuously monitor your integration health.
Health checks
Set up automated checks for API connectivity and critical functions.
// monitoring/healthCheck.ts
import { LomiSDK } from '@lomi./sdk';
// import db from './database'; // Your database connection
export async function checkServiceHealth(): Promise<{
status: string;
errors: string[];
}> {
const errors: string[] = [];
const lomi = new LomiSDK({
apiKey: process.env.LOMI_API_KEY!,
baseUrl: process.env.LOMI_API_URL!,
});
try {
// Check lomi. API status (e.g., list providers)
await lomi.providers.listProviders();
} catch (error: any) {
errors.push(`lomi. API check failed: ${error.message}`);
}
// try {
// // Check Database health
// await db.raw('SELECT 1');
// } catch (error: any) {
// errors.push(`Database check failed: ${error.message}`);
// }
// Check essential internal services...
return {
status: errors.length === 0 ? 'healthy' : 'unhealthy',
errors: errors,
};
}Metrics collection
Track key metrics related to payments and webhooks.
// monitoring/metrics.ts
export function collectMetrics(): Record<string, any> {
// Example metrics (implementation depends on your monitoring tools)
return {
// Payment metrics
payments_processed_total: getTotalPayments(),
payments_succeeded_rate: getSuccessRate(),
payment_api_latency_ms: getAverageApiLatency(),
// Webhook metrics
webhooks_received_total: getTotalWebhooksReceived(),
webhook_verification_failures_total: getWebhookVerificationFailures(),
webhook_processing_latency_ms: getAverageWebhookProcessingTime(),
// System metrics
// system_error_rate: getErrorRate(),
// system_cpu_usage: getCPUUsage(),
};
}Rollback procedures
Have a plan to quickly revert to a previous stable version if a deployment introduces issues.
Automated rollback
Integrate rollback steps into your deployment workflow.
// scripts/rollback.ts
async function automaticRollback(
failedDeploymentId: string,
previousVersion: string,
): Promise<void> {
console.log(
`Rolling back deployment ${failedDeploymentId} to version ${previousVersion}...`,
);
try {
// 1. Stop traffic to the failed version (if applicable)
// await stopTraffic(failedDeploymentId);
// 2. Redeploy the previous stable version
await deployToEnvironment('production', previousVersion);
// 3. Verify rollback success
const health = await checkHealth('production');
if (!health.ok) {
throw new Error('Rollback verification failed');
}
console.log(`Rollback to ${previousVersion} successful and verified.`);
// 4. Notify team
// await notifyTeam(`Rollback completed for deployment ${failedDeploymentId}. Restored version ${previousVersion}.`);
} catch (error: any) {
console.error(`Automatic rollback failed: ${error.message}`);
// await notifyTeam(`CRITICAL: Automatic rollback failed for deployment ${failedDeploymentId}. Manual intervention required.`);
throw error; // Re-throw to signal CI failure
}
}Next steps
Testing guide
This guide covers best practices for testing your lomi. integration, ensuring your payment flows work correctly in both sandbox and production environments.
lomi. CLI
Master the lomi. Command Line Interface for project initialization, authentication, webhook management, and streamlined development workflows.