কাস্টম ওয়েবসাইটে পেমেন্ট কনফার্মেশন: অর্ডার তৈরি, webhook ও HMAC সিগনেচার যাচাই
নিজের তৈরি ওয়েবসাইটে ওয়ালেট পেমেন্ট কনফার্মেশন যোগ করতে হলে প্রবাহটা এমন: সার্ভার থেকে REST API দিয়ে একটা অর্ডার বানান, গ্রাহককে রেসপন্সের paymentUrl-এ পাঠান, তারপর পেমেন্ট হলে QRPayBD যে সাইন করা webhook পাঠায় সেটা গ্রহণ করুন। webhook-এর HMAC সিগনেচার raw বডির ওপর যাচাই না করে অর্ডার পেইড মার্ক করবেন না। এখানে QRPayBD কীভাবে পেমেন্ট নিশ্চিত করে এবং আপনার সার্ভারে কী করতে হবে, সংক্ষেপে দেখানো হলো।
ধাপ ১: অর্ডার তৈরি করুন
আপনার সার্ভার থেকে POST /orders পাঠান। amount হলো টাকার অঙ্ক, আর 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"}'রেসপন্সে paymentUrl পাবেন। API key শুধু আপনার সার্ভারে রাখুন, ব্রাউজারে বা মোবাইল অ্যাপে কখনো নয়।
ধাপ ২: গ্রাহককে paymentUrl-এ পাঠান
গ্রাহকের ব্রাউজারকে paymentUrl-এ রিডাইরেক্ট করুন। পেজে আপনার ওয়ালেট নম্বর, ঠিক কত টাকা দিতে হবে, অর্ডারের রেফারেন্স (QP-XXXX) আর TrxID লেখার ঘর থাকে। গ্রাহক নিজের ওয়ালেট অ্যাপে সেন্ড মানি করেন। অ্যাপে রেফারেন্স ঘর থাকলে সেখানে QP-XXXX লেখেন, নইলে পেজে TrxID লেখেন। আপনার দোকানের ফোনের Collector অ্যাপ পেমেন্টের এসএমএস পাঠালে QRPayBD মিলিয়ে দেখে।
গ্রাহক আপনার সাইটে ফিরে এসেছেন বলেই অর্ডার পেইড ধরবেন না। শুধু সাইন করা webhook, অথবা আপনার সার্ভার থেকে করা স্ট্যাটাস যাচাই পেমেন্ট নিশ্চিত করে।
ধাপ ৩: webhook-এর হেডার ও পেলোড
অর্ডার পেইড হলে QRPayBD আপনার webhook ঠিকানায় JSON বডিসহ POST পাঠায়। হেডারগুলো হলো:
- X-QRPayBD-Signature: sha256=<hex>, যেখানে hex হলো রিকোয়েস্টের raw বডির HMAC-SHA256, আপনার webhook সিক্রেট দিয়ে।
- X-QRPayBD-Event: ইভেন্টের নাম।
- X-QRPayBD-Delivery: ডেলিভারির আইডি।
বডিতে এই ঘরগুলো থাকে:
- event, orderId, storeOrderId, referenceCode
- amountPaisa: অর্ডারের মোট অঙ্ক পয়সায়
- receivedAmountPaisa ও amountMismatch: পেমেন্ট মেসেজে কত টাকা এসেছে বলে লেখা ছিল, আর তা অর্ডারের সঙ্গে না মিললে amountMismatch
- matchMethod: কীভাবে মেলানো হয়েছে
- trxId ও paidAt
HMAC সিগনেচার কীভাবে যাচাই করবেন
সবচেয়ে বড় ভুল হলো JSON পার্স করে আবার স্ট্রিং বানিয়ে HMAC বের করা। তাতে বাইট বদলে যেতে পারে। সিগনেচার হয় যে বাইটগুলো আপনি পেয়েছেন ঠিক সেগুলোর ওপর, তাই raw বডি দিয়ে হিসাব করুন। তারপর constant-time তুলনা ব্যবহার করুন, সাধারণ == নয়। নিচে Node.js ও Express-এর একটা সাধারণ নমুনা। এটা শুধু ধারণা বোঝানোর জন্য, নিজের প্রজেক্টে ঢোকানোর আগে পরীক্ষা করে নিন।
const crypto = require('node:crypto');
const express = require('express');
const app = express();
// raw বডি লাগবে: সিগনেচার হুবহু পাঠানো বাইটের ওপর
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.get('X-QRPayBD-Signature') || '');
const a = Buffer.from(received);
const b = Buffer.from(expected);
if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
return res.status(401).end();
}
const event = JSON.parse(req.body.toString('utf8'));
// দ্রুত 200 দিন, ধীর কাজ পরে করুন
res.status(200).end();
handlePaid(event).catch(console.error);
});timingSafeEqual দুই বাফারের দৈর্ঘ্য সমান না হলে এরর দেয়, তাই আগে দৈর্ঘ্য মিলিয়ে নেওয়া হয়েছে। handlePaid আপনার নিজের ফাংশন। সেখানে কী করবেন, তা পরের অংশে।
হ্যান্ডলারে কী কী করবেন
- দ্রুত 2xx উত্তর দিন। ধীর কাজ, যেমন ইমেইল বা স্টক আপডেট, উত্তর দেওয়ার পরে করুন।
- idempotent রাখুন। orderId (বা আপনার storeOrderId) দিয়ে দেখে নিন অর্ডার আগেই পেইড কি না। একই ডেলিভারি একাধিকবার এলে দ্বিতীয়বার কিছু করবেন না।
- amountPaisa আপনার নিজের অর্ডার মোটের সঙ্গে মেলান। amountMismatch true হলে নিজে থেকে পণ্য ছাড়বেন না, আগে যাচাই করুন।
- অর্ডার পেইড করুন এবং হিসাবের জন্য trxId রেখে দিন।
webhook হারালে কী হবে? রিকনসাইল করুন
ব্যর্থ webhook ডেলিভারি QRPayBD এখনো আবার চেষ্টা করে না। আপনার সার্ভার তখন বন্ধ বা ধীর থাকলে নোটিফিকেশন হারিয়ে যেতে পারে। তাই কয়েক মিনিট পরপর একটা জব চালিয়ে আপনার পেন্ডিং অর্ডারগুলোর জন্য GET /orders/:id ডাকুন। status paid হলে সেটাকে webhook-এর মতোই সামলান। webhook ঠিকানা অবশ্যই পাবলিক https:// ঠিকানা হতে হবে।
মনে রাখার মতো সীমা
- QRPayBD দোকানের অ্যান্ড্রয়েড ফোনের এসএমএস পড়ে পেমেন্ট কনফার্ম করে। এটা অফিসিয়াল ওয়ালেট API নয়। এসএমএস দেরিতে আসতে পারে, মিস হতে পারে বা জাল হতে পারে। বড় অঙ্কে ওয়ালেট অ্যাপে ব্যালান্স দেখে নিন।
- বিকাশ, নগদ ও উপায়ের মেসেজ রিডার আসল পেমেন্টে যাচাই করা হয়েছে, রকেট ও ব্যাংক পরিকল্পনায়।
- দোকানের ফোন চালু ও ইন্টারনেটে না থাকলে কনফার্মেশন দেরি হয়। মিল না হওয়া পেমেন্ট ড্যাশবোর্ডের ইনবক্সে জমা থাকে।
- চ্যাটে পাঠানোর মতো পেমেন্ট লিংক এখনো নেই। আর্লি অ্যাক্সেস চলাকালীন বিনামূল্যে।
রিকোয়েস্ট ও রেসপন্সের পুরো বিবরণ, PHP উদাহরণ, ত্রুটির কোড আর লঞ্চের আগের চেকলিস্ট ইন্টিগ্রেশন গাইডে আছে।