شارژ كيف پول
نمونه پياده سازي جريان شارژ کيف پول با Payexa در Node.js.
دانلود ثبت شده
115
آخرین بروزرسانی
2026-09-25
حجم بسته
17.0 KB
منتشرکننده
مدیر ارشد سامانه
وضعیت نمایش
عمومی و فعال
در این صفحه بسته های آماده برای اتصال به سرویس پرداخت، افزونه های کمکی و مثال های اجرایی را مثل یک ریپازیتوری مرور می کنید: فایل ها را می بینید، README را می خوانید و کل بسته را با یک دانلود می گیرید.
CONTROLLED RELEASE
انتشار کنترل شده از پنل رسمی
هر بسته از مسیر مدیریتی رسمی پی اکسا منتشر می شود و قبل از دانلود، اطلاعات کلیدی آن به صورت شفاف نمایش داده می شود.
PRE-DOWNLOAD VISIBILITY
شفافیت محتوا پیش از دریافت
پیش نمایش README، مرور ساختار فایل و نمایش متادیتای بسته کمک می کند قبل از دانلود، ارزیابی دقیق تری از محتوا داشته باشید.
TRUST PROFILE
نمای رسمی تر برای انتخاب ابزار
صفحه بر پایه شفافیت انتشار، نمایش منبع README، تاریخ بروزرسانی و آمار دانلود چیده شده تا حس ارزیابی حرفه ای تری منتقل کند.
مرجع حقوقی و هویتی کنار دسترس
ساختار صفحه طوری چیده شده که اطلاعات انتشار، محتوای فایل ها و جزئیات هر بسته بدون شلوغی اضافه در دسترس باشند.
نمونه پياده سازي جريان شارژ کيف پول با Payexa در Node.js.
دانلود ثبت شده
115
آخرین بروزرسانی
2026-09-25
حجم بسته
17.0 KB
منتشرکننده
مدیر ارشد سامانه
وضعیت نمایش
عمومی و فعال
پوشه جاری را انتخاب کنید یا برای فایل های متنی پیش نمایش بگیرید.
| نام | نوع | اندازه |
|---|---|---|
| بازگشت به پوشه قبل | پوشه | - |
| views | پوشه | - |
| .env.example | دانلودی | 0.9 KB |
| app.js | قابل پیش نمایش | 7.6 KB |
| package-lock.json | قابل پیش نمایش | 35.9 KB |
| package.json | قابل پیش نمایش | 0.3 KB |
| README.md | قابل پیش نمایش | 1.2 KB |
nodejs-express/app.js
const express = require("express");
const dotenv = require("dotenv");
const axios = require("axios");
const crypto = require("crypto");
const path = require("path");
dotenv.config({ path: path.join(__dirname, ".env") });
const app = express();
app.set("view engine", "ejs");
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
const cfg = {
baseUrl: (process.env.PAYEXA_BASE_URL || "https://sandbox.pexn.ir").replace(/\/$/, ""),
apiKey: process.env.PAYEXA_API_KEY || "",
startPayPath: process.env.PAYEXA_STARTPAY_PATH || "/startPay",
requestEndpoint: process.env.PAYEXA_REQUEST_ENDPOINT || "/v1/payment/request",
verifyEndpoint: process.env.PAYEXA_VERIFY_ENDPOINT || "/v1/payment/verify",
callbackPath: process.env.PAYEXA_CALLBACK_PATH || "/payments/callback",
timeoutMs: Number(process.env.PAYEXA_TIMEOUT_MS || 12000),
badgeScriptUrl: process.env.PAYEXA_BADGE_SCRIPT_URL || "",
port: Number(process.env.PORT || 5051),
};
const wallet = { ownerName: "Demo User", balance: 0 };
const orders = [];
function buildStartPayUrl(authority) {
const path = cfg.startPayPath.startsWith("/") ? cfg.startPayPath : `/${cfg.startPayPath}`;
return `${cfg.baseUrl}${path}?authority=${encodeURIComponent(authority)}`;
}
function genOrderRef() {
return `TOPUP-${crypto.randomBytes(6).toString("hex").toUpperCase()}`;
}
function gatewayHeaders() {
return {
"Content-Type": "application/json",
"X-API-KEY": cfg.apiKey,
};
}
async function requestPayment(amount, callbackUrl, orderRef) {
const url = `${cfg.baseUrl}${cfg.requestEndpoint}`;
const payload = { amount, callback_url: callbackUrl, meta: { order_ref: orderRef } };
const response = await axios.post(url, payload, {
headers: gatewayHeaders(),
timeout: cfg.timeoutMs,
validateStatus: () => true,
});
return { statusCode: response.status, data: response.data || {} };
}
async function verifyPayment(orderId, token) {
const url = `${cfg.baseUrl}${cfg.verifyEndpoint}`;
const payload = { order_id: orderId, token };
const response = await axios.post(url, payload, {
headers: gatewayHeaders(),
timeout: cfg.timeoutMs,
validateStatus: () => true,
});
return { statusCode: response.status, data: response.data || {} };
}
app.get("/", (req, res) => {
const flash = req.query.msg || "";
res.render("index", {
wallet,
orders: [...orders].reverse().slice(0, 15),
badgeScriptUrl: cfg.badgeScriptUrl,
flash,
});
});
app.post("/wallet/charge", async (req, res) => {
const amount = Number(req.body.amount || 0);
if (!Number.isInteger(amount) || amount <= 0) {
return res.redirect("/?msg=" + encodeURIComponent("مبلغ نامعتبر است."));
}
const orderRef = genOrderRef();
const order = {
orderRef,
amount,
status: "pending",
credited: false,
authority: "",
gatewayOrderId: "",
gatewayToken: "",
callbackPayload: null,
verifyResponse: null,
createdAt: new Date().toISOString(),
};
orders.push(order);
const callbackUrl = `${req.protocol}://${req.get("host")}${cfg.callbackPath}`;
try {
const r = await requestPayment(amount, callbackUrl, orderRef);
if (r.statusCode !== 200 && r.statusCode !== 201) {
order.status = "request_failed";
order.verifyResponse = r.data;
return res.redirect("/?msg=" + encodeURIComponent(`خطا در ايجاد پرداخت (${r.statusCode})`));
}
order.authority = String(r.data.authority || "").trim();
order.gatewayOrderId = String(r.data.order_id || "").trim();
if (r.data.amount_unique !== undefined && r.data.amount_unique !== null) {
order.gatewayToken = String(r.data.amount_unique);
}
order.status = "requested";
if (!order.authority) {
order.status = "request_invalid_response";
return res.redirect("/?msg=" + encodeURIComponent("پاسخ درگاه authority نداشت."));
}
return res.redirect(buildStartPayUrl(order.authority));
} catch (err) {
order.status = "request_failed";
return res.redirect("/?msg=" + encodeURIComponent("خطا در ارتباط با درگاه"));
}
});
app.all(cfg.callbackPath, async (req, res) => {
const payload = Object.keys(req.body || {}).length ? req.body : req.query;
const callbackStatus = String(payload.status || "").toUpperCase().trim();
const authority = String(payload.authority || "").trim();
const orderId = String(payload.order_id || "").trim();
const token = String(payload.token || "").trim();
const successStatuses = new Set(["OK", "SUCCESS"]);
if (callbackStatus && !successStatuses.has(callbackStatus)) {
return res.render("payment_result", {
ok: false,
title: "پرداخت ناموفق يا لغو شده",
message: `وضعيت بازگشتي درگاه: ${callbackStatus}`,
payload,
wallet,
});
}
let order = null;
if (orderId) order = orders.find((x) => x.gatewayOrderId === orderId) || null;
if (!order && authority) order = orders.find((x) => x.authority === authority) || null;
if (!order) {
return res.render("payment_result", {
ok: false,
title: "سفارش پيدا نشد",
message: "سفارش مرتبط با callback يافت نشد.",
payload,
wallet,
});
}
order.callbackPayload = payload;
if (token) order.gatewayToken = token;
if (order.credited) {
return res.render("payment_result", {
ok: true,
title: "پرداخت قبلا ثبت شده",
message: "اين سفارش قبلا وريفاي و به کيف پول اضافه شده است.",
payload,
wallet,
});
}
const finalOrderId = orderId || order.gatewayOrderId;
const finalToken = token || order.gatewayToken;
if (!finalOrderId || !finalToken) {
order.status = "callback_invalid";
return res.render("payment_result", {
ok: false,
title: "callback ناقص",
message: "order_id يا token موجود نيست.",
payload,
wallet,
});
}
try {
const vr = await verifyPayment(finalOrderId, finalToken);
order.verifyResponse = vr.data;
if (vr.statusCode === 200 && !order.credited) {
order.status = "verified";
order.credited = true;
wallet.balance += order.amount;
return res.render("payment_result", {
ok: true,
title: "شارژ موفق کيف پول",
message: `مبلغ ${order.amount.toLocaleString("fa-IR")} با موفقيت اضافه شد.`,
payload: vr.data,
wallet,
});
}
if (vr.statusCode === 201) {
order.status = "already_verified";
return res.render("payment_result", {
ok: true,
title: "قبلا وريفاي شده",
message: "اين پرداخت قبلا وريفاي شده است.",
payload: vr.data,
wallet,
});
}
order.status = "verify_failed";
return res.render("payment_result", {
ok: false,
title: "وريفاي ناموفق",
message: `verify failed: ${vr.statusCode}`,
payload: vr.data,
wallet,
});
} catch (_err) {
order.status = "verify_failed";
return res.render("payment_result", {
ok: false,
title: "وريفاي ناموفق",
message: "خطا در ارتباط با درگاه هنگام وريفاي پرداخت",
payload,
wallet,
});
}
});
app.get("/orders/:orderRef", (req, res) => {
const order = orders.find((x) => x.orderRef === req.params.orderRef);
if (!order) return res.status(404).send("Order not found");
return res.render("order_status", { order, wallet });
});
app.listen(cfg.port, () => {
console.log(`Node demo running on http://127.0.0.1:${cfg.port}`);
});
منبع: README.md
نمونه پياده سازي جريان شارژ کيف پول با Payexa در Node.js.
هدف اين مثال، نمايش جريان کامل پرداخت (request -> redirect -> callback -> verify) به شکل ساده و قابل تست است.
cd examples/nodejs-express
cp .env.example .env
npm install
npm start
آدرس پيش فرض:
http://127.0.0.1:5051/
فايل نمونه: .env.example
متغيرهاي مهم:
PAYEXA_BASE_URL براي sandbox/productionPAYEXA_API_KEY کليد مرچنتPAYEXA_STARTPAY_PATH مسير startPayPAYEXA_REQUEST_ENDPOINT و PAYEXA_VERIFY_ENDPOINTPAYEXA_CALLBACK_PATH مسير callbackنکته تست:
PAYEXA به عنوان API key استفاده کني.credited استفاده شده است.من دستیار پی اکسا هستم، شما را در تمام مسیر راهنمایی میکنم و اگر به من نیازی ندارید با ۲ بار کلیک خاموش میشوم.