Development Environment Setup
Recommended: Always start development using our staging environment to avoid affecting live data.
Environment Configuration
Configure your application to use the appropriate environment:
// Environment configuration
const config = {
staging: {
// SMS, USSD, Checkout APIs
baseUrl: 'https://api.staging.kairosafrika.com/v1',
// Payment API
paymentBaseUrl: 'https://api.staging.kairosafrika.cloud/paygw',
apiKey: process.env.KAIROS_STAGING_API_KEY
},
production: {
// SMS, USSD, Checkout APIs
baseUrl: 'https://api.kairosafrika.com/v1',
// Payment API
paymentBaseUrl: 'https://api.kairosafrika.cloud/paygw',
apiKey: process.env.KAIROS_PRODUCTION_API_KEY
}
};
const environment = process.env.NODE_ENV === 'production' ? 'production' : 'staging';
const apiConfig = config[environment];
Error Handling
Implement robust error handling for all API calls:
async function sendSMS(data) {
try {
const response = await fetch(`${apiConfig.baseUrl}/sms`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiConfig.apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
if (!response.ok) {
const error = await response.json();
throw new Error(`API Error: ${error.message}`);
}
return await response.json();
} catch (error) {
console.error('SMS sending failed:', error);
throw error;
}
}
Rate Limiting
Handle rate limits gracefully:
async function apiCallWithRetry(url, options, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const response = await fetch(url, options);
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After') || 60;
console.log(`Rate limited. Retrying after ${retryAfter} seconds...`);
await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
continue;
}
return response;
} catch (error) {
if (attempt === maxRetries) throw error;
await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
}
}
}
Testing
Unit Testing
// tests/sms.test.js
const { sendSMS } = require('../src/sms');
// Mock the API
jest.mock('node-fetch');
const fetch = require('node-fetch');
describe('SMS API', () => {
beforeEach(() => {
fetch.mockClear();
});
test('should send SMS successfully', async () => {
const mockResponse = {
messageId: 'msg_123',
status: 'sent'
};
fetch.mockResolvedValue({
ok: true,
json: () => Promise.resolve(mockResponse)
});
const result = await sendSMS({
to: ['+254700000000'],
message: 'Test message'
});
expect(result.messageId).toBe('msg_123');
expect(fetch).toHaveBeenCalledWith(
expect.stringContaining('/sms'),
expect.objectContaining({
method: 'POST'
})
);
});
});
Logging and Monitoring
Implement comprehensive logging:
const winston = require('winston');
const logger = winston.createLogger({
level: 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
),
transports: [
new winston.transports.File({ filename: 'api-calls.log' }),
new winston.transports.Console()
]
});
async function loggedApiCall(endpoint, data) {
const startTime = Date.now();
try {
logger.info('API call started', { endpoint, data });
const result = await makeApiCall(endpoint, data);
logger.info('API call successful', {
endpoint,
duration: Date.now() - startTime,
resultId: result.id
});
return result;
} catch (error) {
logger.error('API call failed', {
endpoint,
duration: Date.now() - startTime,
error: error.message
});
throw error;
}
}
Security Best Practices
Never commit API keys to version control. Always use environment variables.
API Key Management
- Environment Variables: Store API keys in environment variables
- Key Rotation: Regularly rotate your API keys
- Least Privilege: Use separate keys for different environments
- Monitoring: Monitor API key usage for unusual activity
Request Security
- Always use HTTPS
- Validate all input data
- Implement request signing for sensitive operations
- Use webhook signature verification
Troubleshooting
Cause: Invalid or missing API keySolution:
- Verify your API key is correct
- Check that the Authorization header is properly formatted
- Ensure you’re using the right key for the environment
Cause: Too many requests in a short periodSolution:
- Implement exponential backoff
- Check the
Retry-After header
- Consider upgrading your plan for higher limits
Webhook Not Receiving Events
Cause: Webhook endpoint issuesSolution:
- Verify your webhook URL is accessible
- Check webhook signature verification
- Ensure your endpoint returns 200 status
- Check webhook logs in your dashboard