Skip to main content

Security Best Practices

This guide covers security best practices for integrating the ZenPays SDK into your application.

API Key Security

Environment Variables

Always store API keys in environment variables:

// ✅ Good - using environment variables
const zenpays = new ZenPays({
apiKey: process.env.ZENPAYS_API_KEY!,
})

// ❌ Bad - hardcoded API key
const zenpays = new ZenPays({
apiKey: 'zp_live_abc123...',
})

Key Rotation

Regularly rotate your API keys to minimize exposure:

// Create a new key
const newKey = await zenpays.merchants.createApiKey({
name: 'Rotated Key - Q4 2024',
environment: 'production',
scopes: ['payments:write', 'refunds:write'],
})

// Update your environment with the new key
// Then revoke the old key
await zenpays.merchants.revokeApiKey('old_key_id')

Minimal Scopes

Only grant the permissions each key needs:

// For a read-only dashboard
const dashboardKey = await zenpays.merchants.createApiKey({
name: 'Dashboard Read-Only',
environment: 'production',
scopes: ['payments:read', 'analytics:read'],
})

// For payment processing
const paymentKey = await zenpays.merchants.createApiKey({
name: 'Payment Processor',
environment: 'production',
scopes: ['payments:write'],
})

Network Security

IP Whitelisting

Restrict API access to known IP addresses:

// Add your server IPs
await zenpays.merchants.addIPToWhitelist('203.0.113.50', 'Production Server')
await zenpays.merchants.addIPToWhitelist('203.0.113.51', 'Backup Server')

TLS/HTTPS

The SDK always uses HTTPS for API communication. Never disable TLS verification in production:

// The SDK enforces HTTPS by default
const zenpays = new ZenPays({
apiKey: process.env.ZENPAYS_API_KEY!,
// baseUrl defaults to https://api.zenpays.com
})

Authentication Security

Two-Factor Authentication

Enable 2FA for all team members with API access:

// Setup 2FA
const setup = await zenpays.security.setup2FA()

// Store backup codes securely
console.log('Backup codes:', setup.backupCodes)

// Verify to complete setup
await zenpays.security.verify2FA({ code: '123456' })

Session Management

For user-facing applications, implement proper session handling:

// Use short-lived sessions
const session = await authenticate(user)

// Invalidate sessions on logout
await zenpays.security.revokeSession(sessionId)

Webhook Security

Signature Verification

Always verify webhook signatures:

import { verifyWebhookSignature } from 'zenpays'

app.post('/webhooks/zenpays', (req, res) => {
const signature = req.headers['x-zenpays-signature']
const webhookSecret = process.env.ZENPAYS_WEBHOOK_SECRET!

const isValid = verifyWebhookSignature(
JSON.stringify(req.body),
signature,
webhookSecret
)

if (!isValid) {
return res.status(401).send('Invalid signature')
}

// Process the webhook
handleWebhook(req.body)
res.status(200).send('OK')
})

Replay Attack Prevention

Check webhook timestamps to prevent replay attacks:

function handleWebhook(payload: WebhookPayload) {
const timestamp = new Date(payload.timestamp)
const now = new Date()
const fiveMinutes = 5 * 60 * 1000

if (now.getTime() - timestamp.getTime() > fiveMinutes) {
throw new Error('Webhook too old - possible replay attack')
}

// Process the webhook...
}

Data Security

PCI Compliance

Never handle raw card data on your servers. Use the checkout flow:

// ✅ Good - using checkout link
const intent = await zenpays.payments.createPaymentIntent({
amount: 5000,
currency: 'USD',
})

// Redirect customer to secure checkout
const checkoutUrl = await zenpays.checkout.createCheckoutLink(intent.id)

Sensitive Data Handling

Never log sensitive information:

// ✅ Good - logging safe fields only
console.log(`Payment ${payment.id} - Amount: ${payment.amount}`)

// ❌ Bad - logging sensitive data
console.log('Payment details:', JSON.stringify(payment))

Error Handling

Don't Expose Internal Errors

Show generic messages to users:

try {
await zenpays.payments.createPaymentIntent(data)
}
catch (error) {
// Log detailed error for debugging
console.error('Payment error:', error)

// Show generic message to user
throw new Error('Payment processing failed. Please try again.')
}

Security Monitoring

Monitor Security Events

Regularly review security events:

const events = await zenpays.security.listSecurityEvents({
from: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000), // Last 7 days
type: ['login_failed', 'api_key_used', 'suspicious_activity'],
})

events.data.forEach((event) => {
console.log(`${event.type} at ${event.createdAt} from ${event.ipAddress}`)
})

Set Up Alerts

Configure webhooks for security events:

await zenpays.merchants.createWebhook({
url: 'https://your-app.com/security-alerts',
events: [
'security.suspicious_activity',
'security.api_key_revoked',
'security.login_failed',
],
})

Checklist

Before going to production:

  • API keys stored in environment variables
  • API keys have minimal required scopes
  • IP whitelisting enabled
  • Webhook signature verification implemented
  • 2FA enabled for all team members
  • Security event monitoring configured
  • No sensitive data in logs
  • Error messages don't expose internal details

Next Steps