> ## Documentation Index
> Fetch the complete documentation index at: https://docs.moduluslabs.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Production Deployment

> Deploy your QR payment integration to production

## Overview

This guide walks you through transitioning from sandbox to production, ensuring your QR payment integration is secure, reliable, and ready for real transactions.

<Warning>
  Production involves real money transactions. Complete all testing in sandbox before going live.
</Warning>

## Prerequisites

Before moving to production, ensure you have:

<Steps>
  <Step title="Complete Integration">
    * Successfully created QR codes in sandbox
    * Tested payment flow end-to-end
    * Implemented webhook handling
    * Added proper error handling
    * Tested all edge cases and error scenarios
  </Step>

  <Step title="Security Review">
    * Credentials stored securely (environment variables, secrets manager)
    * HTTPS enabled on all endpoints
    * Webhook endpoint secured
    * Input validation implemented
    * Logging and monitoring configured
  </Step>

  <Step title="Business Requirements">
    * Business verification completed with Modulus Labs
    * Legal agreements signed
    * Bank account for settlements configured
    * Customer support process established
  </Step>
</Steps>

## Sandbox vs Production

| Aspect              | Sandbox                           | Production                    |
| ------------------- | --------------------------------- | ----------------------------- |
| **Base URL**        | `https://qrph.sbx.moduluslabs.io` | `https://qrph.moduluslabs.io` |
| **Secret Key**      | Starts with `sk_test_`            | Starts with `sk_live_`        |
| **Encryption Key**  | Test encryption key               | Production encryption key     |
| **Activation Code** | Test activation code              | Production activation code    |
| **Transactions**    | Simulated                         | Real money                    |
| **Webhooks**        | Manual simulation                 | Automatic from banks          |
| **Rate Limits**     | 100 requests/minute               | 1000 requests/minute          |
| **QR Validity**     | 15 minutes                        | 15 minutes                    |
| **Support**         | Developer support                 | 24/7 production support       |

## Getting Production Credentials

<Steps>
  <Step title="Contact Modulus Labs">
    Email **[production@moduluslabs.io](mailto:production@moduluslabs.io)** with:

    * Company name and registration details
    * Business verification documents
    * Expected transaction volume
    * Technical contact information
  </Step>

  <Step title="Complete Verification">
    Modulus Labs will:

    * Verify your business identity
    * Review your integration
    * Conduct security assessment
    * Process legal agreements
  </Step>

  <Step title="Receive Credentials">
    Upon approval, you'll receive:

    * **Production Secret Key** (`sk_live_...`)
    * **Production Encryption Key**
    * **Production Activation Code** (`XXXX-XXXX-XXXX-XXXX`)
    * **Production Base URL**
    * **Webhook IP Whitelist**
  </Step>
</Steps>

<Note>
  Production credential approval typically takes 3-5 business days after document submission.
</Note>

## Environment Configuration

### 1. Separate Environment Variables

Never mix sandbox and production credentials. Use separate environment files:

<CodeGroup>
  ```bash .env.production theme={null}
  # Production Modulus Labs Credentials
  MODULUS_BASE_URL=https://qrph.moduluslabs.io
  MODULUS_SECRET_KEY=sk_live_YOUR_PRODUCTION_SECRET_KEY
  MODULUS_ENCRYPTION_KEY=YOUR_PRODUCTION_ENCRYPTION_KEY
  MODULUS_ACTIVATION_CODE=XXXX-XXXX-XXXX-XXXX

  # Environment
  NODE_ENV=production
  ```

  ```bash .env.sandbox theme={null}
  # Sandbox Modulus Labs Credentials
  MODULUS_BASE_URL=https://qrph.sbx.moduluslabs.io
  MODULUS_SECRET_KEY=sk_test_YOUR_SANDBOX_SECRET_KEY
  MODULUS_ENCRYPTION_KEY=YOUR_SANDBOX_ENCRYPTION_KEY
  MODULUS_ACTIVATION_CODE=TEST-TEST-TEST-TEST

  # Environment
  NODE_ENV=development
  ```
</CodeGroup>

### 2. Load Based on Environment

```javascript config.js theme={null}
require('dotenv').config({
  path: process.env.NODE_ENV === 'production'
    ? '.env.production'
    : '.env.sandbox'
});

module.exports = {
  modulus: {
    baseUrl: process.env.MODULUS_BASE_URL,
    secretKey: process.env.MODULUS_SECRET_KEY,
    encryptionKey: process.env.MODULUS_ENCRYPTION_KEY,
    activationCode: process.env.MODULUS_ACTIVATION_CODE
  },
  environment: process.env.NODE_ENV || 'development'
};
```

### 3. Use Secrets Manager (Recommended)

For production, use a secrets manager instead of `.env` files:

<Tabs>
  <Tab title="AWS Secrets Manager">
    ```javascript theme={null}
    const AWS = require('aws-sdk');
    const secretsManager = new AWS.SecretsManager({
      region: 'ap-southeast-1'
    });

    async function getSecrets() {
      const data = await secretsManager.getSecretValue({
        SecretId: 'prod/modulus-labs'
      }).promise();

      const secrets = JSON.parse(data.SecretString);

      return {
        secretKey: secrets.MODULUS_SECRET_KEY,
        encryptionKey: secrets.MODULUS_ENCRYPTION_KEY,
        activationCode: secrets.MODULUS_ACTIVATION_CODE
      };
    }
    ```
  </Tab>

  <Tab title="Google Secret Manager">
    ```javascript theme={null}
    const {SecretManagerServiceClient} = require('@google-cloud/secret-manager');
    const client = new SecretManagerServiceClient();

    async function getSecrets() {
      const projectId = 'your-project-id';

      const [secretKey] = await client.accessSecretVersion({
        name: `projects/${projectId}/secrets/modulus-secret-key/versions/latest`
      });

      const [encryptionKey] = await client.accessSecretVersion({
        name: `projects/${projectId}/secrets/modulus-encryption-key/versions/latest`
      });

      const [activationCode] = await client.accessSecretVersion({
        name: `projects/${projectId}/secrets/modulus-activation-code/versions/latest`
      });

      return {
        secretKey: secretKey.payload.data.toString(),
        encryptionKey: encryptionKey.payload.data.toString(),
        activationCode: activationCode.payload.data.toString()
      };
    }
    ```
  </Tab>

  <Tab title="Azure Key Vault">
    ```javascript theme={null}
    const { DefaultAzureCredential } = require('@azure/identity');
    const { SecretClient } = require('@azure/keyvault-secrets');

    async function getSecrets() {
      const keyVaultName = 'your-key-vault';
      const KVUri = `https://${keyVaultName}.vault.azure.net`;

      const credential = new DefaultAzureCredential();
      const client = new SecretClient(KVUri, credential);

      const secretKey = await client.getSecret('modulus-secret-key');
      const encryptionKey = await client.getSecret('modulus-encryption-key');
      const activationCode = await client.getSecret('modulus-activation-code');

      return {
        secretKey: secretKey.value,
        encryptionKey: encryptionKey.value,
        activationCode: activationCode.value
      };
    }
    ```
  </Tab>
</Tabs>

## Production Checklist

Before deploying to production, verify each item:

### Security

<Accordion title="Credentials Management">
  * [ ] Production credentials stored in secrets manager (not in code)
  * [ ] `.env` files added to `.gitignore`
  * [ ] No credentials in version control history
  * [ ] Secret rotation policy established
  * [ ] Access to production credentials restricted to authorized personnel only
</Accordion>

<Accordion title="HTTPS & Transport Security">
  * [ ] All API calls use HTTPS (never HTTP)
  * [ ] Valid SSL/TLS certificate installed
  * [ ] TLS 1.2 or higher enforced
  * [ ] Certificate expiration monitoring configured
</Accordion>

<Accordion title="Webhook Security">
  * [ ] Webhook endpoint uses HTTPS
  * [ ] Webhook payload decryption implemented
  * [ ] Firewall configured to accept only Modulus Labs IPs
  * [ ] Request origin validation implemented
  * [ ] Rate limiting configured
</Accordion>

<Accordion title="Input Validation">
  * [ ] Amount validation (1.00 - 99,999.99)
  * [ ] Currency code validation (PHP only)
  * [ ] Merchant reference number validation (1-36 chars)
  * [ ] Activation code format validation
  * [ ] SQL injection prevention
  * [ ] XSS prevention for user-facing displays
</Accordion>

### Reliability

<Accordion title="Error Handling">
  * [ ] All API calls wrapped in try-catch
  * [ ] Proper error logging implemented
  * [ ] User-friendly error messages
  * [ ] Retry logic for transient failures
  * [ ] Circuit breaker pattern for API failures
  * [ ] Graceful degradation when API unavailable
</Accordion>

<Accordion title="Monitoring & Alerting">
  * [ ] API response time monitoring
  * [ ] Error rate tracking
  * [ ] Webhook delivery monitoring
  * [ ] Transaction volume monitoring
  * [ ] Alerting configured for critical failures
  * [ ] Health check endpoints implemented
</Accordion>

<Accordion title="Logging">
  * [ ] All API requests logged (excluding sensitive data)
  * [ ] All webhook receipts logged
  * [ ] Transaction IDs tracked
  * [ ] Log retention policy configured
  * [ ] Log aggregation service configured
</Accordion>

### Performance

<Accordion title="Scalability">
  * [ ] Load testing completed
  * [ ] Auto-scaling configured
  * [ ] Database connection pooling implemented
  * [ ] Caching strategy for QR codes if needed
  * [ ] CDN configured for static assets
</Accordion>

<Accordion title="Rate Limiting">
  * [ ] Client-side rate limiting implemented
  * [ ] Exponential backoff for retries
  * [ ] Request queuing for high traffic
  * [ ] 429 (Too Many Requests) handling
</Accordion>

### Compliance

<Accordion title="Data Protection">
  * [ ] PII handling compliant with regulations
  * [ ] Data retention policy established
  * [ ] Audit trail for all transactions
  * [ ] Customer data encrypted at rest
  * [ ] Privacy policy updated
</Accordion>

<Accordion title="Business Operations">
  * [ ] Settlement account configured
  * [ ] Reconciliation process established
  * [ ] Refund process documented
  * [ ] Customer support trained
  * [ ] Dispute resolution process defined
</Accordion>

## Deployment Process

### 1. Pre-deployment Testing

```bash theme={null}
# Run full test suite
npm test

# Run integration tests against sandbox
npm run test:integration

# Run security audit
npm audit

# Check for outdated dependencies
npm outdated
```

### 2. Deploy to Staging

Deploy to a staging environment that mirrors production:

```bash theme={null}
# Build application
npm run build

# Deploy to staging
npm run deploy:staging

# Run smoke tests
npm run test:smoke:staging

# Verify staging with production credentials (in controlled test)
```

### 3. Deploy to Production

<Steps>
  <Step title="Schedule Deployment">
    Choose low-traffic period for deployment (e.g., 2 AM local time)
  </Step>

  <Step title="Notify Stakeholders">
    Alert customer support, operations team, and key stakeholders
  </Step>

  <Step title="Create Backup">
    ```bash theme={null}
    # Backup database
    npm run db:backup

    # Tag current production version
    git tag -a v1.0.0-prod -m "Pre-deployment backup"
    ```
  </Step>

  <Step title="Deploy">
    ```bash theme={null}
    # Deploy application
    npm run deploy:production

    # Run post-deployment checks
    npm run test:smoke:production
    ```
  </Step>

  <Step title="Verify">
    * Test health check endpoint
    * Create a small test transaction (₱1.00)
    * Verify webhook delivery
    * Check monitoring dashboards
    * Review logs for errors
  </Step>

  <Step title="Monitor">
    Actively monitor for 1-2 hours after deployment:

    * Error rates
    * Response times
    * Transaction success rates
    * Webhook delivery rates
  </Step>
</Steps>

### 4. Rollback Plan

Prepare a rollback plan in case issues arise:

```bash theme={null}
# Quick rollback to previous version
npm run deploy:rollback

# Or restore from backup
git checkout v1.0.0-prod
npm run deploy:production
```

## Production URL Configuration

Update all API calls to use production URL:

```javascript theme={null}
// Before (Sandbox)
const BASE_URL = 'https://qrph.sbx.moduluslabs.io';

// After (Production)
const BASE_URL = 'https://qrph.moduluslabs.io';

// Better - Use environment variable
const BASE_URL = process.env.MODULUS_BASE_URL;
```

### Verify No Sandbox URLs Remain

```bash theme={null}
# Search for hardcoded sandbox URLs
grep -r "qrphsandbox" .

# Should return no results in production code
```

## Production Best Practices

<CardGroup cols={2}>
  <Card title="Idempotency" icon="arrows-rotate">
    Use unique `merchantReferenceNumber` for each transaction to prevent duplicates
  </Card>

  <Card title="Retry Logic" icon="repeat">
    Implement exponential backoff with max retries (3-5 attempts)
  </Card>

  <Card title="Timeouts" icon="clock">
    Set appropriate timeouts (10-30 seconds for API calls)
  </Card>

  <Card title="Circuit Breaker" icon="power-off">
    Fail fast when API is down, prevent cascading failures
  </Card>

  <Card title="Monitoring" icon="chart-line">
    Track success rates, latency, and error rates in real-time
  </Card>

  <Card title="Logging" icon="file-lines">
    Log all transactions with sufficient detail for debugging
  </Card>

  <Card title="Alerts" icon="bell">
    Set up alerts for error spikes, latency increases, webhook failures
  </Card>

  <Card title="Documentation" icon="book">
    Maintain runbooks for common production issues
  </Card>
</CardGroup>

## Monitoring Production

### Key Metrics to Track

```javascript theme={null}
const metrics = {
  // API Health
  apiResponseTime: 'Average response time for QR creation',
  apiErrorRate: 'Percentage of API calls that fail',
  apiAvailability: 'Uptime percentage',

  // Business Metrics
  qrCodesCreated: 'Total QR codes generated',
  transactionsCompleted: 'Successful payments',
  transactionValue: 'Total payment volume',
  conversionRate: 'QR scans to completed payments',

  // Webhook Metrics
  webhooksReceived: 'Total webhooks received',
  webhookProcessingTime: 'Time to process webhook',
  webhookFailureRate: 'Percentage of webhook processing failures',

  // Performance
  databaseQueryTime: 'Average DB query duration',
  serverCPU: 'CPU utilization',
  serverMemory: 'Memory utilization',
  requestsPerMinute: 'API request rate'
};
```

### Example Monitoring Setup

<CodeGroup>
  ```javascript Prometheus theme={null}
  const prometheus = require('prom-client');

  // Create metrics
  const qrCreationCounter = new prometheus.Counter({
    name: 'qr_codes_created_total',
    help: 'Total number of QR codes created'
  });

  const qrCreationDuration = new prometheus.Histogram({
    name: 'qr_creation_duration_seconds',
    help: 'QR code creation duration in seconds',
    buckets: [0.1, 0.5, 1, 2, 5]
  });

  const apiErrorCounter = new prometheus.Counter({
    name: 'api_errors_total',
    help: 'Total number of API errors',
    labelNames: ['error_code']
  });

  // Use in code
  async function createQR(amount, ref) {
    const timer = qrCreationDuration.startTimer();

    try {
      const result = await modulusApi.createQR(amount, ref);
      qrCreationCounter.inc();
      return result;
    } catch (error) {
      apiErrorCounter.inc({ error_code: error.code });
      throw error;
    } finally {
      timer();
    }
  }
  ```

  ```javascript DataDog theme={null}
  const { metrics } = require('datadog-metrics');

  metrics.init({
    host: 'your-app',
    prefix: 'modulus.',
    flushIntervalSeconds: 15
  });

  async function createQR(amount, ref) {
    const startTime = Date.now();

    try {
      const result = await modulusApi.createQR(amount, ref);

      metrics.increment('qr.created');
      metrics.histogram('qr.creation_time', Date.now() - startTime);
      metrics.gauge('qr.amount', parseFloat(amount));

      return result;
    } catch (error) {
      metrics.increment('qr.error', 1, [`error:${error.code}`]);
      throw error;
    }
  }
  ```

  ```javascript CloudWatch theme={null}
  const AWS = require('aws-sdk');
  const cloudwatch = new AWS.CloudWatch({ region: 'ap-southeast-1' });

  async function recordMetric(name, value, unit = 'Count') {
    await cloudwatch.putMetricData({
      Namespace: 'ModulusLabs/QR',
      MetricData: [{
        MetricName: name,
        Value: value,
        Unit: unit,
        Timestamp: new Date()
      }]
    }).promise();
  }

  async function createQR(amount, ref) {
    const startTime = Date.now();

    try {
      const result = await modulusApi.createQR(amount, ref);

      await recordMetric('QRCodesCreated', 1);
      await recordMetric('QRCreationTime', Date.now() - startTime, 'Milliseconds');

      return result;
    } catch (error) {
      await recordMetric('APIErrors', 1);
      throw error;
    }
  }
  ```
</CodeGroup>

## Handling Production Issues

### Common Production Issues

<AccordionGroup>
  <Accordion title="API Rate Limiting (429 Error)">
    **Symptoms:**

    * HTTP 429 responses
    * Increased latency
    * Failed QR creations

    **Solutions:**

    1. Implement request queuing
    2. Add exponential backoff
    3. Cache QR codes when appropriate
    4. Contact Modulus Labs to increase rate limit

    ```javascript theme={null}
    const queue = new PQueue({ concurrency: 10, interval: 60000 });

    async function createQRWithRateLimit(amount, ref) {
      return queue.add(() => modulusApi.createQR(amount, ref));
    }
    ```
  </Accordion>

  <Accordion title="Webhook Delivery Failures">
    **Symptoms:**

    * Payments not updating in system
    * Manual reconciliation needed
    * Customer complaints

    **Solutions:**

    1. Check webhook endpoint health
    2. Review firewall rules
    3. Verify SSL certificate
    4. Check webhook processing logs
    5. Contact Modulus Labs to resend webhooks

    ```javascript theme={null}
    // Emergency webhook replay script
    async function replayWebhooks(transactionIds) {
      // Contact support@moduluslabs.io with transaction IDs
      // They can manually resend webhooks
    }
    ```
  </Accordion>

  <Accordion title="High Error Rates">
    **Symptoms:**

    * Sudden spike in API errors
    * Multiple error codes
    * Customer complaints

    **Solutions:**

    1. Check Modulus Labs status page
    2. Review recent code changes
    3. Check production credentials haven't expired
    4. Verify network connectivity
    5. Review error logs for patterns

    ```bash theme={null}
    # Check error patterns
    grep "ERROR" app.log | cut -d' ' -f5 | sort | uniq -c | sort -nr

    # Check API connectivity
    curl https://qrph.moduluslabs.io/ping \
      -u $MODULUS_SECRET_KEY:
    ```
  </Accordion>

  <Accordion title="Performance Degradation">
    **Symptoms:**

    * Slow QR code generation
    * Timeouts
    * Poor user experience

    **Solutions:**

    1. Check database performance
    2. Review application logs
    3. Scale horizontally (add more servers)
    4. Optimize database queries
    5. Implement caching

    ```javascript theme={null}
    // Add caching for frequently accessed data
    const redis = require('redis');
    const client = redis.createClient();

    async function getQRWithCache(transactionId) {
      const cached = await client.get(`qr:${transactionId}`);
      if (cached) return JSON.parse(cached);

      const qr = await database.getQR(transactionId);
      await client.setex(`qr:${transactionId}`, 300, JSON.stringify(qr));
      return qr;
    }
    ```
  </Accordion>
</AccordionGroup>

### Emergency Contacts

<CardGroup cols={2}>
  <Card title="Production Support" icon="headset">
    **Email:** [support@moduluslabs.io](mailto:support@moduluslabs.io)
    **Phone:** Available in partner portal
    **SLA:** \< 1 hour response for critical issues
  </Card>

  <Card title="Status Page" icon="signal">
    **URL:** status.moduluslabs.io
    Check for ongoing incidents or maintenance
  </Card>

  <Card title="Technical Support" icon="code">
    **Email:** [tech@moduluslabs.io](mailto:tech@moduluslabs.io)
    For integration and API questions
  </Card>

  <Card title="Account Manager" icon="user">
    Contact your dedicated account manager
    For business and billing questions
  </Card>
</CardGroup>

## Production Maintenance

### Regular Tasks

<Steps>
  <Step title="Daily">
    * Monitor error rates and alerts
    * Review transaction volumes
    * Check webhook delivery rates
    * Scan security logs
  </Step>

  <Step title="Weekly">
    * Review performance metrics
    * Analyze transaction patterns
    * Update documentation
    * Review and address technical debt
  </Step>

  <Step title="Monthly">
    * Rotate API keys (if policy requires)
    * Update dependencies and security patches
    * Review and optimize database
    * Conduct security audit
    * Business reconciliation
  </Step>

  <Step title="Quarterly">
    * Disaster recovery drill
    * Load testing
    * Review SLAs and performance
    * Update runbooks
    * Security penetration testing
  </Step>
</Steps>

### Key Rotation

Rotate production credentials periodically:

```bash theme={null}
# 1. Generate new credentials via partner portal

# 2. Update secrets manager with new credentials
aws secretsmanager update-secret \
  --secret-id prod/modulus-labs \
  --secret-string '{
    "MODULUS_SECRET_KEY": "sk_live_NEW_KEY",
    "MODULUS_ENCRYPTION_KEY": "NEW_ENCRYPTION_KEY"
  }'

# 3. Deploy with new credentials
npm run deploy:production

# 4. Verify new credentials work
npm run test:smoke:production

# 5. Revoke old credentials
# Contact support@moduluslabs.io to revoke old API key
```

## Scaling for Growth

As your transaction volume grows:

### Horizontal Scaling

```javascript theme={null}
// Use load balancer to distribute requests
// across multiple application instances

// Example: AWS Auto Scaling
const autoscaling = {
  minInstances: 2,
  maxInstances: 10,
  targetCPU: 70,
  targetMemory: 80
};

// Scale based on metrics
if (requestsPerMinute > 500) {
  scaleUp();
}
```

### Database Optimization

```javascript theme={null}
// Connection pooling
const pool = new Pool({
  max: 20,
  min: 5,
  idleTimeoutMillis: 30000
});

// Read replicas for queries
const writeDB = connectToMaster();
const readDB = connectToReplica();

// Use read replica for non-critical reads
async function getTransactionHistory(merchantRef) {
  return readDB.query(
    'SELECT * FROM transactions WHERE merchant_ref = $1',
    [merchantRef]
  );
}
```

### Caching Strategy

```javascript theme={null}
// Cache QR codes for a short period
const cache = new Map();

async function createQRWithCache(amount, ref) {
  const cacheKey = `${amount}:${ref}`;

  if (cache.has(cacheKey)) {
    const cached = cache.get(cacheKey);
    if (Date.now() - cached.timestamp < 300000) { // 5 minutes
      return cached.data;
    }
  }

  const qr = await modulusApi.createQR(amount, ref);
  cache.set(cacheKey, {
    data: qr,
    timestamp: Date.now()
  });

  return qr;
}
```

## Next Steps

<CardGroup cols={2}>
  <Card title="Webhooks" icon="webhook" href="/docs/webhooks/overview">
    Implement production webhook handling
  </Card>

  <Card title="Monitoring Setup" icon="chart-line" href="#monitoring-production">
    See monitoring examples above for Prometheus, DataDog, and CloudWatch
  </Card>

  <Card title="API Reference" icon="book" href="/api-reference/qr/create">
    Review production API documentation
  </Card>

  <Card title="Support" icon="headset" href="mailto:support@moduluslabs.io">
    Contact production support team
  </Card>
</CardGroup>

<Check>
  **You're ready for production!** Follow this guide carefully and don't hesitate to contact Modulus Labs support if you need assistance.
</Check>
