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_CREDITSerror handling - Alerts when credits < threshold (e.g., 10 credits)
- Automatic or manual recharge process configured
✅ Orange Money
- Payment webhooks configured and tested
-
PENDING,SUCCESSFUL,FAILEDstatus 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