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

# Security Best Practices

> Secure your integration with proper authentication and data handling

## API Key Security

### Storage

<Warning>
  Never commit API keys to version control or expose them in client-side code.
</Warning>

```javascript theme={null}
// ❌ Bad: Hardcoded in source code
const API_KEY = "sk_live_abc123";

// ✅ Good: Use environment variables
const API_KEY = process.env.FLEXY_API_KEY;
```

### Environment Variables

```bash theme={null}
# .env file
FLEXY_API_KEY=sk_live_your_key_here
FLEXY_SANDBOX_KEY=sk_test_your_sandbox_key
API_BASE_URL=https://api.oneclickdz.com
```

```javascript theme={null}
// Load environment variables
require("dotenv").config();

const apiKey = process.env.FLEXY_API_KEY;
```

### Key Rotation

```javascript theme={null}
// Support multiple keys for zero-downtime rotation
const API_KEYS = {
  primary: process.env.FLEXY_API_KEY_PRIMARY,
  secondary: process.env.FLEXY_API_KEY_SECONDARY,
};

async function callApiWithRotation(endpoint, data) {
  try {
    return await callApi(endpoint, data, API_KEYS.primary);
  } catch (error) {
    if (error.status === 401) {
      // Try secondary key
      return await callApi(endpoint, data, API_KEYS.secondary);
    }
    throw error;
  }
}
```

## HTTPS Enforcement

```javascript theme={null}
// Always use HTTPS
const API_BASE_URL = "https://api.oneclickdz.com";

// Reject self-signed certificates in production
const axios = require("axios");
const https = require("https");

const client = axios.create({
  baseURL: API_BASE_URL,
  httpsAgent: new https.Agent({
    rejectUnauthorized: process.env.NODE_ENV === "production",
  }),
});
```

## Request Validation

```javascript theme={null}
// Validate all inputs before sending to API
const Joi = require("joi");

const mobileTopupSchema = Joi.object({
  plan_code: Joi.string().required(),
  MSSIDN: Joi.string()
    .pattern(/^0[567][0-9]{8}$/)
    .required(),
  amount: Joi.number()
    .min(50)
    .max(5000)
    .when("plan_code", {
      is: Joi.string().pattern(/^DYN/),
      then: Joi.required(),
      otherwise: Joi.forbidden(),
    }),
  reference: Joi.string().max(100).required(),
});

function validateTopupRequest(data) {
  const { error, value } = mobileTopupSchema.validate(data);
  if (error) {
    throw new Error(`Validation error: ${error.message}`);
  }
  return value;
}
```

## Sensitive Data Handling

### Don't Log Sensitive Data

```javascript theme={null}
// ❌ Bad: Logs API key
console.log("Request:", {
  headers: { "X-Access-Token": apiKey },
  body: data,
});

// ✅ Good: Redact sensitive info
function sanitizeLog(data) {
  const sanitized = { ...data };
  if (sanitized.headers?.X-Access-Token) {
    sanitized.headers.X-Access-Token = "***REDACTED***";
  }
  return sanitized;
}

console.log("Request:", sanitizeLog(request));
```

### Protect Phone Numbers

```javascript theme={null}
// Mask phone numbers in logs/UI
function maskPhone(phone) {
  if (phone.length !== 10) return phone;
  return phone.slice(0, 4) + "****" + phone.slice(-2);
}

console.log("Top-up sent to:", maskPhone("0551234567")); // 0551****67
```

### Secure Card Codes

```javascript theme={null}
// Never log full card codes
function maskCardCode(code) {
  if (code.length <= 4) return "****";
  return "****" + code.slice(-4);
}

// Store securely
await db.orders.create({
  data: {
    userId: user.id,
    cardCode: encrypt(cardCode), // Encrypt sensitive data
    cardCodeMasked: maskCardCode(cardCode),
  },
});
```

## Rate Limiting

```javascript theme={null}
// Implement client-side rate limiting
const rateLimit = require("express-rate-limit");

const apiLimiter = rateLimit({
  windowMs: 60 * 1000, // 1 minute
  max: 60, // Max 60 requests per minute
  message: "Too many requests, please try again later",
});

app.use("/api/topup", apiLimiter, topupHandler);
```

## IP Whitelisting

<Info>
  Contact support to whitelist your server IPs for additional security.
</Info>

```javascript theme={null}
// Make requests from whitelisted IPs only
const WHITELISTED_IPS = ["192.168.1.100", "10.0.0.50"];

function isWhitelisted(ip) {
  return WHITELISTED_IPS.includes(ip);
}

app.use((req, res, next) => {
  const clientIp = req.ip;
  if (!isWhitelisted(clientIp)) {
    return res.status(403).json({ error: "Forbidden" });
  }
  next();
});
```

## Audit Logging

```javascript theme={null}
// Log all API interactions for audit
async function auditLog(event, data) {
  await db.auditLogs.create({
    data: {
      timestamp: new Date(),
      event,
      userId: data.userId,
      action: data.action,
      ipAddress: data.ip,
      userAgent: data.userAgent,
      requestId: data.requestId,
      success: data.success,
      // Don't log sensitive data
      metadata: sanitize(data.metadata),
    },
  });
}

// Usage
await auditLog("topup_sent", {
  userId: user.id,
  action: "SEND_MOBILE_TOPUP",
  ip: req.ip,
  userAgent: req.get("user-agent"),
  requestId: response.requestId,
  success: true,
});
```

## Error Messages

```javascript theme={null}
// Don't expose internal details in error messages
function getSafeErrorMessage(error) {
  // Internal errors
  if (error.status >= 500) {
    return {
      message: "An error occurred. Please try again later.",
      code: "INTERNAL_ERROR",
      requestId: error.requestId, // Include for support
    };
  }

  // Client errors - be specific but safe
  return {
    message: error.message,
    code: error.code,
    requestId: error.requestId,
  };
}
```

## Secure Configuration

```javascript theme={null}
// Separate configs for sandbox/production
const config = {
  sandbox: {
    apiKey: process.env.FLEXY_SANDBOX_KEY,
    baseUrl: "https://api.oneclickdz.com",
    testMode: true,
    logLevel: "debug",
  },
  production: {
    apiKey: process.env.FLEXY_API_KEY,
    baseUrl: "https://api.oneclickdz.com",
    testMode: false,
    logLevel: "error",
  },
};

const env = process.env.NODE_ENV || "sandbox";
const currentConfig = config[env];
```

## Dependency Security

```bash theme={null}
# Regularly audit dependencies
npm audit

# Update vulnerable packages
npm audit fix

# Use tools like Snyk
npm install -g snyk
snyk test
```

## Encryption at Rest

```javascript theme={null}
// Encrypt sensitive data before storing
const crypto = require("crypto");

const ENCRYPTION_KEY = process.env.ENCRYPTION_KEY; // 32-byte key
const IV_LENGTH = 16;

function encrypt(text) {
  const iv = crypto.randomBytes(IV_LENGTH);
  const cipher = crypto.createCipheriv(
    "aes-256-cbc",
    Buffer.from(ENCRYPTION_KEY),
    iv
  );
  let encrypted = cipher.update(text);
  encrypted = Buffer.concat([encrypted, cipher.final()]);
  return iv.toString("hex") + ":" + encrypted.toString("hex");
}

function decrypt(text) {
  const parts = text.split(":");
  const iv = Buffer.from(parts.shift(), "hex");
  const encrypted = Buffer.from(parts.join(":"), "hex");
  const decipher = crypto.createDecipheriv(
    "aes-256-cbc",
    Buffer.from(ENCRYPTION_KEY),
    iv
  );
  let decrypted = decipher.update(encrypted);
  decrypted = Buffer.concat([decrypted, decipher.final()]);
  return decrypted.toString();
}

// Usage
const cardCode = "1234-5678-9012";
const encrypted = encrypt(cardCode);
await db.orders.create({ data: { cardCode: encrypted } });
```

## Security Checklist

<Steps>
  <Step title="API Keys">
    ✓ Stored in environment variables ✓ Not committed to version control ✓
    Rotated periodically
  </Step>

  <Step title="HTTPS">
    ✓ All requests use HTTPS ✓ Certificate validation enabled
  </Step>

  <Step title="Input Validation">
    ✓ All inputs validated before API calls ✓ Schema validation in place
  </Step>

  <Step title="Logging">
    ✓ Sensitive data not logged ✓ Audit logs enabled ✓ Request IDs tracked
  </Step>

  <Step title="Rate Limiting">
    ✓ Client-side rate limiting ✓ Retry logic with backoff
  </Step>

  <Step title="Data Protection">
    ✓ Sensitive data encrypted at rest ✓ Phone numbers masked in logs ✓ Card
    codes secured
  </Step>
</Steps>

## Best Practices Summary

<CardGroup cols={2}>
  <Card title="Never Expose Keys" icon="key">
    Use environment variables
  </Card>

  <Card title="Always Use HTTPS" icon="lock">
    Secure all communications
  </Card>

  <Card title="Validate Everything" icon="circle-check">
    Check inputs before sending
  </Card>

  <Card title="Encrypt Sensitive Data" icon="shield">
    Protect data at rest
  </Card>
</CardGroup>

## Related

<CardGroup cols={2}>
  <Card title="Authentication" href="/en/authentication">
    API key setup
  </Card>

  <Card title="Error Handling" href="error-handling-best-practices">
    Handle errors securely
  </Card>
</CardGroup>
