Security
1. Protect Your API Keys
Never expose API keys in frontend code or public repositories!
# .env file (add to .gitignore)
ONECLICK_API_KEY=your_key_here
const apiKey = process.env.ONECLICK_API_KEY;
2. Backend Only
Always call OCPay API from your backend, never from frontend:
// β WRONG - Frontend
fetch("https://api.oneclickdz.com/v3/ocpay/createLink", {
headers: { "X-Access-Token": "YOUR_KEY" }, // Exposed to users!
});
// β
CORRECT - Backend
// Frontend calls YOUR API, your backend calls OneClick
fetch("/api/create-payment", { method: "POST" });
function validateOrderData(data) {
if (!Number.isInteger(data.amount)) {
throw new Error("Amount must be integer");
}
if (data.amount < 500 || data.amount > 500000) {
throw new Error("Amount must be between 500 and 500,000 DZD");
}
if (!data.title || data.title.trim().length === 0) {
throw new Error("Title is required");
}
return data;
}
4. Verify Before Fulfillment
Always verify payment status on backend before fulfilling orders!
async function fulfillOrder(orderId) {
const order = await db.orders.findOne({ id: orderId });
// CRITICAL: Verify payment status
const response = await fetch(
`https://api.oneclickdz.com/v3/ocpay/checkPayment/${order.paymentRef}`,
{
headers: { "X-Access-Token": process.env.ONECLICK_API_KEY },
}
);
const data = await response.json();
if (data.data.status !== "CONFIRMED") {
throw new Error("Payment not confirmed");
}
// Safe to fulfill
await processOrder(order);
}
Error Handling
Handle API Errors
async function createPaymentSafe(orderId, amount, title) {
try {
const response = await fetch(
"https://api.oneclickdz.com/v3/ocpay/createLink",
{
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Access-Token": process.env.ONECLICK_API_KEY,
},
body: JSON.stringify({
productInfo: { title, amount },
}),
}
);
if (!response.ok) {
if (response.status === 403) {
throw new Error("Merchant not validated");
}
throw new Error("API request failed");
}
const data = await response.json();
if (!data.success) {
throw new Error(data.error?.message || "Unknown error");
}
return data.data;
} catch (error) {
console.error("Payment creation failed:", error);
throw error;
}
}
Testing
Use Sandbox
Test with sandbox keys before production:
# Development
ONECLICK_API_KEY=sk_sandbox_abc123...
# Production
ONECLICK_API_KEY=sk_live_xyz789...
Test Scenarios
Test these cases:
- β
Successful payment
- β
Failed payment
- β
Expired payment link (20 min)
- β
Customer returns without paying
- β
API errors
Production Checklist
Before going live:
Security
Functionality
Testing
Monitoring
Common Mistakes
Avoid these:
- β Hardcoding API keys
- β Calling API from frontend
- β Not saving paymentRef
- β Fulfilling without verification
- β No error handling
- β Checking too frequently (respect rate limits)
- β Not testing in sandbox first
Database Best Practices
Add indexes for performance:
-- Speed up pending order queries
CREATE INDEX idx_orders_pending
ON orders(status, payment_ref)
WHERE status = 'PENDING';
-- Speed up paymentRef lookups
CREATE INDEX idx_payment_ref ON orders(payment_ref);
Logging
Log important events:
// Log payment creation
console.log("[Payment] Created", {
orderId,
paymentRef,
amount,
timestamp: new Date(),
});
// Log status changes
console.log("[Payment] Status changed", {
orderId,
oldStatus: "PENDING",
newStatus: "PAID",
timestamp: new Date(),
});
Next Steps
Youβre Ready! π
You now have everything to accept payments with OCPay. Start with sandbox, test thoroughly, then go live!