Skip to main content

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

  1. Environment Variables: Store API keys in environment variables
  2. Key Rotation: Regularly rotate your API keys
  3. Least Privilege: Use separate keys for different environments
  4. 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
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