Skip to main content

Overview

You need to check payment status because bank processing is asynchronous. Use two simple methods:
  1. Cron job: Check pending orders every 20 minutes
  2. Manual check: When customer views their order

Method 1: Cron Job (Every 20 Minutes)

const cron = require("node-cron");

// Run every 20 minutes
cron.schedule("*/20 * * * *", async () => {
  console.log("Checking pending payments...");

  try {
    // Get pending orders from last 24 hours
    const pendingOrders = await db.orders.find({
      status: "PENDING",
      paymentRef: { $exists: true },
      createdAt: { $gte: new Date(Date.now() - 24 * 60 * 60 * 1000) },
    });

    for (const order of pendingOrders) {
      await checkAndUpdateOrder(order.id, order.paymentRef);
      await sleep(100); // Small delay between requests
    }

    console.log(`Checked ${pendingOrders.length} orders`);
  } catch (error) {
    console.error("Cron job error:", error);
  }
});

async function checkAndUpdateOrder(orderId, paymentRef) {
  try {
    const response = await fetch(
      `https://api.oneclickdz.com/v3/ocpay/checkPayment/${paymentRef}`,
      {
        headers: { "X-Access-Token": process.env.ONECLICK_API_KEY },
      }
    );

    const data = await response.json();
    const status = data.data.status;

    if (status === "CONFIRMED") {
      await db.orders.update(orderId, { status: "PAID" });
      console.log(`✅ Order ${orderId} marked as PAID`);
    } else if (status === "FAILED") {
      await db.orders.update(orderId, { status: "FAILED" });
      console.log(`❌ Order ${orderId} marked as FAILED`);
    }
  } catch (error) {
    console.error(`Error checking order ${orderId}:`, error);
  }
}

function sleep(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

Setup Cron Job

Add to your crontab (Linux/Unix):
# Edit crontab
crontab -e

# Add line to run every 20 minutes
*/20 * * * * /usr/bin/node /path/to/cron-job.js >> /var/log/payment-check.log 2>&1

# Or for Python
*/20 * * * * /usr/bin/python3 /path/to/cron-job.py >> /var/log/payment-check.log 2>&1

# Or for PHP
*/20 * * * * /usr/bin/php /path/to/cron-check-payments.php >> /var/log/payment-check.log 2>&1

Method 2: Manual Check (When Customer Views Order)

Already implemented in Step 2! When customer lands on order page, it automatically checks once. Optional: Add a button to check on demand (checks every 1 minute max):
<!DOCTYPE html>
<html>
  <head>
    <title>Order Status</title>
  </head>
  <body>
    <h1>Order Status</h1>
    <p>Status: <span id="status">PENDING</span></p>

    <button id="checkBtn" onclick="startChecking()">
      Check Payment Status
    </button>

    <p id="message"></p>

    <script>
      let checking = false;
      let checkInterval = null;
      const orderId = window.location.pathname.split("/").pop();

      async function checkPayment() {
        const response = await fetch(`/orders/${orderId}/check`, {
          method: "POST",
        });

        const data = await response.json();
        document.getElementById("status").textContent = data.status;

        if (data.status === "CONFIRMED") {
          document.getElementById("message").textContent =
            "✅ Payment confirmed!";
          stopChecking();
          setTimeout(() => location.reload(), 2000);
        } else if (data.status === "FAILED") {
          document.getElementById("message").textContent = "❌ Payment failed";
          stopChecking();
        } else {
          document.getElementById("message").textContent =
            "⏳ Still pending...";
        }
      }

      function startChecking() {
        if (checking) return;

        checking = true;
        document.getElementById("checkBtn").disabled = true;

        // Check immediately
        checkPayment();

        // Then check every 1 minute
        checkInterval = setInterval(checkPayment, 60000);

        // Stop after 10 minutes
        setTimeout(stopChecking, 10 * 60000);
      }

      function stopChecking() {
        checking = false;
        document.getElementById("checkBtn").disabled = false;
        if (checkInterval) {
          clearInterval(checkInterval);
          checkInterval = null;
        }
      }

      // Auto-check when page loads (if pending)
      if (document.getElementById("status").textContent === "PENDING") {
        checkPayment();
      }
    </script>
  </body>
</html>

Summary

Two simple methods:
  1. ✅ Cron job every 20 minutes for all pending orders
  2. ✅ Manual check when customer views order (max every 1 minute)
  3. ✅ Auto-check once when order page loads
This covers all scenarios without overloading the API!

Next Steps

Continue to Best Practices

Learn essential security and error handling