Skip to main content

Production Checklist

Essential verifications before going live with the MONCRENEAU API.

1. API Keys Configuration

✅ Production Keys

  • Production keys generated and stored securely
  • Production keys are stored in environment variables (not hardcoded)
  • Production keys are NOT committed to Git (.env in .gitignore)
  • Key rotation planned (minimum every 6 months)
# ❌ BAD
const apiKey = "YOUR_API_KEY"; // hardcoded in code

# ✅ GOOD
const apiKey = process.env.MONCRENEAU_API_KEY;

✅ Separate Environments

  • Development configuration for local tests
  • Production configuration only in production
  • Different environment variables per environment

2. Webhooks

✅ Configuration

  • Webhook URL in HTTPS (valid SSL certificate)
  • Webhook URL publicly accessible (not localhost)
  • Webhook secret secured (32+ random characters)
  • HMAC signature verification implemented
  • Response in less than 5 seconds
  • Asynchronous processing configured (queue)

✅ Idempotence

  • Event deduplication (tracking by event.id)
  • Handling multiple deliveries of the same event
  • Event replay testing
// Deduplication example
const exists = await db.processedEvents.findOne({
eventId: event.id
});
if (exists) return { status: 'already_processed' };

3. Security

✅ HTTPS

  • All API requests over HTTPS
  • Valid and up-to-date SSL certificate
  • No HTTP in production

✅ Authentication

  • API key in header Authorization: Bearer <key>
  • No API key in URLs (visible in logs)
  • Request timeout configured (30s max)

✅ Rate Limiting

  • Client-side rate limiting implemented (100 requests/min)
  • 429 error handling (Too Many Requests)
  • Exponential backoff for retries
// Rate limiting with p-throttle
const throttle = pThrottle({
limit: 100,
interval: 60000
});

const createAppointment = throttle(async (data) => {
return api.post('/appointments', data);
});

4. Error Handling

✅ Error Codes

  • Handling 4xx errors (validation, insufficient credits)
  • Handling 5xx errors (retry with backoff)
  • Structured error logging with context
  • Alerts on critical errors (Slack, PagerDuty)

✅ Retry Logic

  • Automatic retry for 5xx errors and timeouts
  • Exponential backoff (2s, 4s, 8s, 16s)
  • Maximum 3 attempts
  • Dead letter queue for definitive failures
async function createAppointmentWithRetry(data, maxAttempts = 3) {
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
return await api.post('/appointments', data);
} catch (error) {
if (error.response?.status >= 500 && attempt < maxAttempts) {
await sleep(Math.pow(2, attempt) * 1000);
continue;
}
throw error;
}
}
}

5. Credits and Payments

✅ Credits Management

  • Balance check before appointment creation
  • INSUFFICIENT_CREDITS error handling
  • Alerts when credits < threshold (e.g., 10 credits)
  • Automatic or manual recharge process configured

✅ Orange Money

  • Payment webhooks configured and tested
  • PENDING, SUCCESSFUL, FAILED status handling
  • Payment timeout handled (5 minutes)
  • Automatic credit reload after validated payment

6. Monitoring and Observability

✅ Metrics

  • Number of appointments created/day
  • API request success/error rate
  • Average response time (< 200ms)
  • Number of webhook events received
  • Remaining credits balance
// Example with Prometheus
const apiRequestsTotal = new Counter({
name: 'moncreneau_api_requests_total',
help: 'Total API requests',
labelNames: ['method', 'status']
});

const apiDuration = new Histogram({
name: 'moncreneau_api_duration_seconds',
help: 'API request duration'
});

✅ Logs

  • Structured logs (JSON)
  • Appropriate log level (INFO in prod, DEBUG in dev)
  • Request correlation (request ID)
  • No sensitive data logged (API keys, tokens)
logger.info('Appointment created', {
requestId: req.id,
appointmentId: appointment.id,
organizationId: org.id,
duration: Date.now() - start
});

✅ Alerts

  • Alerts on 5xx errors (> 5% of requests)
  • Alerts on insufficient credits
  • Alerts on payment failures
  • Alerts on unprocessed webhooks (> 1h)

7. Performance

✅ Optimizations

  • Parallel API requests when possible
  • Cache rarely changing data (departments, services)
  • Pagination for lists (max 100 per page)
  • Compression enabled (gzip)
// Create multiple appointments in parallel
const appointments = await Promise.all([
api.post('/appointments', data1),
api.post('/appointments', data2),
api.post('/appointments', data3)
]);

8. Testing

✅ Automated Tests

  • Unit tests for critical functions
  • Integration tests with TEST API
  • Load tests (100 requests/min)
  • Webhook tests (ngrok + test events)
  • Error handling tests

✅ Tested Scenarios

  • Appointment creation
  • Appointment modification
  • Cancellation with credit refund
  • Insufficient credits
  • Webhook received and processed
  • End-to-end Orange Money payment

9. Documentation

✅ Internal Documentation

  • System architecture documented
  • Incident runbook (who to contact, procedures)
  • API key management documented
  • Key rotation process
  • Monitoring dashboard accessible

10. Backup and Rollback

✅ Contingency Plan

  • Rollback strategy defined (< 5 minutes)
  • Critical data backup
  • Feature flags to disable features
  • MONCRENEAU emergency contact known

Final Verification

Before launch:


# 1. Check environment variables
env | grep MONCRENEAU

# 2. Test API connection
curl -H "Authorization: Bearer $MONCRENEAU_API_KEY" https://mc-prd.duckdns.org/api/v1/appointments

# 3. Verify webhooks
curl -X POST https://your-app.com/webhooks/test -H "Content-Type: application/json" -d '{"id":"evt_test","type":"appointment.created"}'

# 4. Check monitoring
open https://monitoring.your-app.com

# 5. Verify alerts
# Send a test alert

Resources