আপনার ওয়েবসাইটে QRPayBD যুক্ত করুন
এই গাইড ডেভেলপারদের জন্য, যাঁরা নিজের তৈরি ওয়েবসাইট বা অ্যাপে QRPayBD যুক্ত করছেন। আপনার সার্ভার একটি অর্ডার তৈরি করে, গ্রাহককে QRPayBD-র পেমেন্ট পেজে পাঠায় এবং সাইন করা ওয়েবহুকের মাধ্যমে পেমেন্টের খবর পায়।
কীভাবে কাজ করে
আপনার সার্ভার চার ধাপে QRPayBD-র সঙ্গে কাজ করে:
- আপনার সার্ভার টাকার অঙ্ক ও আপনার নিজের অর্ডার নম্বর দিয়ে একটি অর্ডার তৈরি করে।
- আপনি গ্রাহককে পেমেন্ট পেজে পাঠান (রেসপন্সের paymentUrl)। সেখানে আপনার দোকানের ওয়ালেট নম্বর, সঠিক অঙ্ক ও অর্ডারের রেফারেন্স দেখানো হয়।
- গ্রাহক নিজের ওয়ালেট অ্যাপে অর্ডারের রেফারেন্সসহ টাকা পাঠান। অ্যাপে রেফারেন্স ঘর না থাকলে সেই পেজে নিজের পেমেন্ট মেসেজের TrxID লেখেন।
- QRPayBD সেই রেফারেন্স বা TrxID ও অঙ্ক আপনার Collector অ্যাপের পড়া পেমেন্ট এসএমএসের সঙ্গে মেলায়, অর্ডার পেইড করে এবং আপনার সার্ভারে সাইন করা ওয়েবহুক পাঠায়।
QRPayBD কখনো টাকা রাখে না বা সরায় না। যে পেমেন্ট আগেই আপনার নিজের ওয়ালেট বা ব্যাংক অ্যাকাউন্টে পৌঁছেছে, শুধু সেটাই নিশ্চিত করে।
শুরুর আগে
- https://qrpaybd.com/app/ এ অ্যাকাউন্ট খুলুন এবং আপনার ওয়ালেট নম্বরসহ অন্তত একটি পেমেন্ট মাধ্যম যোগ করুন (Store setup, তারপর Payment methods)।
- যে ফোনে আপনার পেমেন্টের এসএমএস আসে সেখানে Collector অ্যাপ ইনস্টল করে অ্যাকাউন্টের সঙ্গে যুক্ত করুন।
- Store setup-এ একটি স্টোর API কী বানান। এটি একবারই দেখানো হয়। এটি আপনার সার্ভারে গোপন রাখুন, কখনো ওয়েব পেজ বা মোবাইল অ্যাপে রাখবেন না।
- Store setup-এ আপনার ওয়েবহুক ঠিকানা (একটি পাবলিক https:// ঠিকানা) দিন এবং সেখানে দেখানো ওয়েবহুক সিক্রেট কপি করুন।
সব উদাহরণে ঠিকানা https://qrpaybd.com ধরা হয়েছে। প্রতিটি রিকোয়েস্টে Authorization: Bearer YOUR_STORE_API_KEY হেডার পাঠান, শুধু আপনার সার্ভার থেকে।
ধাপ ১: অর্ডার তৈরি করুন
আপনার সার্ভার থেকে POST /orders পাঠান। amount হলো মোট টাকার অঙ্ক, JSON সংখ্যা হিসেবে (দশমিক চলবে)। storeOrderId হলো আপনার নিজের অনন্য অর্ডার নম্বর। returnUrl ঐচ্ছিক: দিলে পেমেন্টের পর পেমেন্ট পেজে দোকানে ফিরে যাওয়ার বোতাম দেখানো হয়।
curl -X POST https://qrpaybd.com/orders \
-H "Authorization: Bearer YOUR_STORE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"amount": 1250.50, "storeOrderId": "ORDER-1001", "returnUrl": "https://yourshop.com/thank-you"}'const res = await fetch("https://qrpaybd.com/orders", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.QRPAYBD_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ amount: 1250.5, storeOrderId: "ORDER-1001" }),
});
if (!res.ok) throw new Error(`QRPayBD error ${res.status}`);
const order = await res.json();
// Redirect the customer's browser to order.paymentUrl$ch = curl_init('https://qrpaybd.com/orders');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('QRPAYBD_API_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode(['amount' => 1250.50, 'storeOrderId' => 'ORDER-1001']),
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($status < 200 || $status >= 300) {
// handle the error
}
$order = json_decode($body, true);
header('Location: ' . $order['paymentUrl']);নতুন অর্ডারে HTTP 201 আসে। একই storeOrderId আবার পাঠালে একই অর্ডারসহ HTTP 200 আসে, তাই টাইমআউট হওয়া রিকোয়েস্ট নিশ্চিন্তে আবার পাঠানো যায়।
{
"orderId": "5b0d2a4e-3f71-4c1e-9a53-7d0f1d2c8e11",
"storeOrderId": "ORDER-1001",
"referenceCode": "QP-7F3K",
"amount": 1250.5,
"status": "pending",
"trxId": null,
"paidAt": null,
"receivedAmountPaisa": null,
"amountMismatch": false,
"matchMethod": null,
"returnUrl": "https://yourshop.com/thank-you",
"paymentUrl": "https://qrpaybd.com/pay/QP-7F3K"
}- orderId হলো অর্ডারের জন্য QRPayBD-র আইডি। অর্ডার দেখতে বা বাতিল করতে এটি ব্যবহার করুন।
- referenceCode একটি ছোট কোড, যেমন QP-7F3K, যা পেমেন্ট পেজে দেখানো হয়।
- status হবে pending, paid বা cancelled।
- paymentUrl হলো যেখানে গ্রাহককে পাঠাবেন।
- trxId, paidAt ও matchMethod অর্ডার পেইড হলে পূরণ হয়।
- receivedAmountPaisa ও amountMismatch জানায় পেমেন্ট মেসেজে কত টাকা এসেছে বলে লেখা ছিল (ধাপ ৩ দেখুন)।
ধাপ ২: গ্রাহককে পেমেন্ট পেজে পাঠান
গ্রাহকের ব্রাউজারকে paymentUrl-এ রিডাইরেক্ট করুন, অথবা লিংক হিসেবে দেখান। পেজে আপনার ওয়ালেট নম্বর, পরিশোধের সঠিক অঙ্ক, ওয়ালেট অ্যাপে লেখার জন্য অর্ডারের রেফারেন্স এবং TrxID লেখার ঘর থাকে। পেজটি বাংলা ও ইংরেজিতে চলে এবং পেমেন্ট নিশ্চিত হলে নিজে থেকেই বদলে যায়।
গ্রাহক আপনার সাইটে ফিরে এসেছেন বলেই অর্ডার পেইড ধরবেন না। শুধু ওয়েবহুক, অথবা আপনার সার্ভার থেকে করা স্ট্যাটাস যাচাই পেমেন্ট নিশ্চিত করে।
ধাপ ৩: পেমেন্ট নিশ্চিত করুন
অর্ডার পেইড হলে QRPayBD আপনার ওয়েবহুক ঠিকানায় একটি JSON বডিসহ POST রিকোয়েস্ট পাঠায়, সঙ্গে X-QRPayBD-Signature, X-QRPayBD-Event ও X-QRPayBD-Delivery হেডার থাকে।
{
"event": "order.paid",
"orderId": "5b0d2a4e-3f71-4c1e-9a53-7d0f1d2c8e11",
"storeOrderId": "ORDER-1001",
"referenceCode": "QP-7F3K",
"amountPaisa": 125050,
"receivedAmountPaisa": 125050,
"amountMismatch": false,
"matchMethod": "trx_claim",
"trxId": "01M2N876B7",
"paidAt": "2026-09-26T09:14:22.000Z"
}রিকোয়েস্টে ভরসা করার আগে সবসময় সিগনেচার যাচাই করুন। সিগনেচার হলো sha256= এবং তার পরে রিকোয়েস্টের হুবহু (raw) বডির HMAC-SHA256, যা আপনার ওয়েবহুক সিক্রেট দিয়ে বানানো, হেক্সাডেসিমালে। আপনি যে বাইটগুলো পেয়েছেন ঠিক সেগুলোর সঙ্গে মেলান, নতুন করে এনকোড করা কপির সঙ্গে নয়।
import crypto from "node:crypto";
import express from "express";
const app = express();
// Use the RAW body: the signature covers the exact bytes that were sent.
app.post("/webhooks/qrpaybd", express.raw({ type: "application/json" }), (req, res) => {
const expected =
"sha256=" +
crypto.createHmac("sha256", process.env.QRPAYBD_WEBHOOK_SECRET).update(req.body).digest("hex");
const received = String(req.headers["x-qrpaybd-signature"] || "");
const ok =
received.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(received), Buffer.from(expected));
if (!ok) return res.status(401).end();
const event = JSON.parse(req.body.toString("utf8"));
// 1. Find your order by event.storeOrderId. Skip it if it is already paid.
// 2. Compare event.amountPaisa with your own order total (in paisa).
// 3. If event.amountMismatch is true, hold the order for a manual check.
// 4. Mark the order paid and keep event.trxId.
res.status(200).json({ ok: true });
});$raw = file_get_contents('php://input');
$expected = 'sha256=' . hash_hmac('sha256', $raw, getenv('QRPAYBD_WEBHOOK_SECRET'));
$received = $_SERVER['HTTP_X_QRPAYBD_SIGNATURE'] ?? '';
if (!hash_equals($expected, $received)) {
http_response_code(401);
exit;
}
$event = json_decode($raw, true);
// Same checks as above: find the order, skip if already paid,
// compare $event['amountPaisa'], look at $event['amountMismatch'], then mark it paid.
http_response_code(200);তারপর আপনার হ্যান্ডলারে:
- storeOrderId দিয়ে অর্ডার খুঁজুন, আর অর্ডার আগেই পেইড হলে ইভেন্টটি উপেক্ষা করুন। একই ডেলিভারি একাধিকবার আসতে পারে।
- amountPaisa (অর্ডারের মোট অঙ্ক পয়সায়, ১০০ পয়সা = ১ টাকা) আপনার নিজের অর্ডার মোটের সঙ্গে মেলান।
- amountMismatch true হলে পেমেন্ট মেসেজে অর্ডারের চেয়ে ভিন্ন অঙ্ক দেখানো ছিল। নিজে থেকে পণ্য ছাড়বেন না, গ্রাহকের সঙ্গে যাচাই করুন।
- অর্ডার পেইড করুন এবং হিসাবের জন্য trxId রেখে দিন।
- যেকোনো 2xx স্ট্যাটাস দিয়ে দ্রুত উত্তর দিন। ধীর কাজ পরে করুন।
ব্যর্থ ওয়েবহুক ডেলিভারি QRPayBD এখনো আবার চেষ্টা করে না, আর ওয়েবহুক ঠিকানা অবশ্যই পাবলিক https:// ঠিকানা হতে হবে। নিরাপদ থাকতে কয়েক মিনিট পরপর GET /orders/ORDER_ID দিয়ে আপনার পেন্ডিং অর্ডারও যাচাই করুন এবং status paid হলে ওয়েবহুকের মতোই ধরুন।
অর্ডার দেখুন বা বাতিল করুন
curl https://qrpaybd.com/orders/ORDER_ID \
-H "Authorization: Bearer YOUR_STORE_API_KEY"curl -X POST https://qrpaybd.com/orders/ORDER_ID/cancel \
-H "Authorization: Bearer YOUR_STORE_API_KEY"
# {"ok": true, "status": "cancelled"}পেন্ডিং অর্ডার বাতিল করলে সেটি বন্ধ হয়ে যায়: পেমেন্ট পেজ সেটিকে বাতিল দেখায় এবং গ্রাহক আর ওই অর্ডারের জন্য পেমেন্ট দাবি করতে পারেন না। পেইড অর্ডার বাতিল করা যায় না (409 order_already_paid)। QRPayBD রিফান্ড করে না: রিফান্ড আপনার নিজের ওয়ালেট বা ব্যাংক থেকে দিতে হয়।
ত্রুটি
- 400 validation_failed: কোনো ঘর নেই বা ভুল, যেমন amount ধনাত্মক সংখ্যা নয় বা returnUrl কোনো http(s) ঠিকানা নয়।
- 401 invalid_api_key: স্টোর API কী নেই, ভুল, অথবা বাতিল করা হয়েছে।
- 404: আপনার অ্যাকাউন্টে এমন কোনো অর্ডার নেই।
- 409 order_already_paid: অর্ডার পেইড, তাই বাতিল করা যাবে না।
- 429: অনেক বেশি রিকোয়েস্ট। একটু অপেক্ষা করে আবার চেষ্টা করুন।
- 5xx: আমাদের দিকে সমস্যা। একটু পরে আবার চেষ্টা করুন। একই storeOrderId আবার পাঠানো নিরাপদ।
ত্রুটির রেসপন্স JSON, যেমন {"error": "invalid_api_key"}।
চালু করার আগে
- API কী ও ওয়েবহুক সিক্রেট শুধু আপনার সার্ভারে রাখুন।
- প্রতিটি ওয়েবহুকের সিগনেচার যাচাই করুন এবং অঙ্ক মেলান।
- storeOrderId ব্যবহার করে একই ডেলিভারি একাধিকবার এলে নিরাপদে সামলান।
- একটি ছোট আসল পেমেন্ট দিয়ে, যেমন ১ টাকা, পুরো প্রক্রিয়া পরীক্ষা করুন।
- ড্যাশবোর্ডের Unmatched অংশ দেখতে থাকুন: নিজে থেকে মেলানো যায়নি এমন পেমেন্ট সেখানে আসে।
যা জেনে রাখা ভালো
- পেমেন্ট নিশ্চিত হয় আপনার Collector অ্যাপের পড়া পেমেন্ট এসএমএস থেকে, কোনো অফিশিয়াল ওয়ালেট API থেকে নয়। ফোন বন্ধ বা অফলাইন থাকলে, বা মেসেজের ধরন আমাদের কাছে নতুন হলে কনফার্মেশনে দেরি হতে পারে বা ড্যাশবোর্ডে হাতে মেলাতে হতে পারে।
- বিকাশ, নগদ ও উপায়ের মেসেজ রিডার আসল পেমেন্টে যাচাই করা হয়েছে; রকেট ও ব্যাংক পরিকল্পনায় আছে।
- গ্রাহককে অর্ডারের সঠিক অঙ্কই পরিশোধ করতে হবে। ভিন্ন অঙ্ক নিজে থেকে নিশ্চিত হয় না।