Security Best Practices
Credential Management
Never hard-code credentials. Store all secrets in environment variables or a dedicated secrets manager.
| Platform | Recommended Service |
|---|---|
| AWS | AWS Secrets Manager |
| Google Cloud | Secret Manager |
| Azure | Azure Key Vault |
| Self-hosted | HashiCorp Vault |
| Any | Environment variables (minimum baseline) |
# ✅ Correct — loaded from environment
const controlKey = process.env.CENTIWISE_CONTROL_KEY;
# ❌ Wrong — hard-coded in source
const controlKey = "abc123secretkey";- Add
.envto.gitignore - Rotate your
merchant_control_keyimmediately if you suspect exposure - Use separate credentials for sandbox and production environments
Transport Security
- Enforce HTTPS with TLS 1.2 or higher on all endpoints, including your
server_callback_url - Do not accept or send credentials over plain HTTP
- Use a valid certificate from a trusted CA on your callback URL (Let's Encrypt is free)
Control Hash Validation
On every incoming callback from Centiwise, recompute the control hash and compare it to the value in the payload (if provided). This confirms the callback originated from Centiwise and the data was not altered in transit.
function isValidCallback(payload) {
const expected = buildControlHash(
payload.client_orderid,
payload.amount,
payload.currency
);
return payload.control === expected;
}IP Allowlisting
Centiwise sends callbacks from a fixed set of IP address- 85.208.60.1
. Ask your account manager for the current list and allowlist those IPs on your callback endpoint at the firewall or application level.
# Nginx example — allow only Centiwise IPs on the callback route
location /callback {
allow 1.2.3.4; # replace with actual Centiwise IPs
allow 5.6.7.8;
deny all;
proxy_pass http://localhost:3000;
}Idempotency
Use client_orderid as an idempotency key. Before processing any payment event (API response or webhook), check whether you have already processed a terminal status for that order.
const order = await db.orders.findOne({ client_orderid });
if (order?.status === 'paid') return; // Already processedThis prevents double-fulfilment caused by network retries or duplicate webhook deliveries.
Logging
- Log all inbound and outbound API interactions for audit trails
- Redact sensitive fields before writing to logs: control keys, raw OAuth signatures
- Retain logs for a minimum of 90 days (or longer per your compliance requirements)
// ✅ Safe to log
console.log({ client_orderid, status, amount, currency });
// ❌ Never log
console.log({ merchant_control_key, oauth_signature });API Timeouts
Always set timeouts on outbound Centiwise API calls to prevent your server from hanging indefinitely:
const response = await axios.post(url, payload, {
timeout: 60000, // 60-second read timeout
});| Timeout Type | Recommended Value |
|---|---|
| Connect timeout | 30 seconds |
| Read timeout | 60 seconds |
PCI DSS Scope
Centiwise is PCI DSS certified. To keep your integration in scope:
- Do not log, store, or transmit raw card numbers or CVVs through your own systems
- Let Centiwise handle card data directly via the hosted payment form (redirect flow)
- Review your PCI DSS SAQ with a qualified security assessor if you are unsure of your scope
Updated 5 months ago
