A complete MonCash checkout flow in Node.js: create, redirect, verify

poze 4 months ago226 gadeen

0

I've read the MonCash docs, but I'm confused about how the pieces connect. Can someone show the whole flow end to end: creating the payment, sending the customer to MonCash, and confirming the payment afterwards?

Anviwònman:Node.js 20Express

Dyagnostik IA

Se IA ki fè l. Se pa yon repons — kominote a anba a konfime oswa korije l. Toujou verifye anvan ou fye l.

1 Repons

3
✓
✓ Repons yo aksepte

Three server-side steps, with the customer's browser in the middle:

[your server] CreatePayment ──► payment token
[browser]     redirect to MonCash page ──► customer enters phone + PIN on MonCash
[MonCash]     redirects to your return URL (?transactionId=…)
[your server] RetrieveTransactionPayment ──► verify amount + status ──► fulfil
// 1. Create the payment (server)
app.post("/checkout/:orderId", async (req, res) => {
  const order = await db.order.findUniqueOrThrow({ where: { id: req.params.orderId } });
  const token = await moncashToken(); // cached token, see the token-expiry question
 
  const r = await fetch(MONCASH.api + "/v1/CreatePayment", {
    method: "POST",
    headers: { Authorization: "Bearer " + token, "Content-Type": "application/json" },
    body: JSON.stringify({ amount: order.totalHtg, orderId: order.id }),
  });
  if (!r.ok) return res.status(502).send("MonCash unavailable, please retry");
  const { payment_token } = await r.json();
 
  // 2. Send the customer to MonCash
  res.redirect(MONCASH.gateway + "/Payment/Redirect?token=" + encodeURIComponent(payment_token.token));
});
 
// 3. Return URL, configured in the MonCash merchant portal
app.get("/moncash/return", async (req, res) => {
  const transactionId = String(req.query.transactionId ?? "");
  const token = await moncashToken();
  const r = await fetch(MONCASH.api + "/v1/RetrieveTransactionPayment", {
    method: "POST",
    headers: { Authorization: "Bearer " + token, "Content-Type": "application/json" },
    body: JSON.stringify({ transactionId }),
  });
  const { payment } = await r.json();
 
  const order = await db.order.findUnique({ where: { id: payment?.reference } });
  const paid = payment?.message === "successful" && order && Number(payment.cost) === order.totalHtg;
  if (!paid) return res.redirect("/orders/payment-failed");
 
  await markPaidOnce(order.id, payment.transaction_id); // idempotent
  res.redirect("/orders/" + order.id + "/thank-you");
});

The rules that matter:

  • Never trust the return URL alone. Anyone can type ?transactionId= into a browser. Always re-fetch the payment from the API.
  • Compare the amount with your order. Don't just check that "a payment" exists.
  • reference is the orderId you sent. Use it to find the order.
  • Make fulfilment idempotent: a refresh of the return page must not ship twice.

Konekte pou di lòt moun si li te mache.

answered 4 months ago

Sign in and verify your email to post an answer.