ডেভেলপার ডকুমেন্টেশন
সব রিকোয়েস্ট যায় এই ঠিকানায়, JSON পাঠান আর JSON পান।
টাকা সবসময় পয়সায় লিখতে হয়: ৫০০ টাকা মানে 50000। সময় UTC-তে, ISO 8601 ফরম্যাটে।
API key
ড্যাশবোর্ডের প্রজেক্ট ও API পাতা (বা টেলিগ্রাম বটের প্রজেক্ট) থেকে Live key বা Test key নিন। key একবারই দেখানো হয়, হারালে নতুন বানাতে হয়। নতুন বানালে আগেরটা সাথে সাথে বন্ধ হয়ে যায়।
Authorization: Bearer sk_live_...
পেমেন্ট পেজ দিয়ে শুরু
সবচেয়ে সহজ উপায়। নম্বর দেখানো, TrxID নেওয়া, ভুল হলে কারণ বলা, সব আমাদের পেজ করে।
- ক্রেতা "কিনুন" চাপলে আপনার সার্ভার invoice বানায়, সাথে
success_url। - ক্রেতাকে উত্তরের
checkout_url-এ পাঠান। - পেমেন্ট সফল হলে ক্রেতা
success_url-এ ফিরে আসে। - অর্ডার চালু করুন webhook এলে। শুধু
success_url-এ ফেরার ওপর ভরসা করবেন না, ওটা যে কেউ খুলতে পারে।
Invoice তৈরি
| ফিল্ড | ধরন | মানে |
|---|---|---|
amountআবশ্যক | integer | পয়সায়। ৫০০ টাকা = 50000 |
reference | string, ২০০ | আপনার নিজের আইডি, যেমন অর্ডার নম্বর। webhook-এ ফেরত আসে |
description | string, ৫০০ | ক্রেতা পেমেন্ট পেজে দেখে |
metadata | object | যা খুশি, ৪০০০ অক্ষর পর্যন্ত। ক্রেতা দেখে না |
expires_in_minutes | integer | ডিফল্ট ৬০, সর্বোচ্চ ১০০৮০ (৭ দিন) |
success_url | string | সফল হলে ক্রেতাকে এখানে ফেরানো হয় |
cancel_url | string | ক্রেতা "ফিরে যান" চাপলে |
currency | string | এখন শুধু BDT |
curl https://telegramdownloadmanager.com/v1/invoices \ -H "Authorization: Bearer $PAYGATE_KEY" \ -H "Content-Type: application/json" \ -d '{ "amount": 50000, "reference": "order_77", "description": "HSC Physics কোর্স", "success_url": "https://shop.example/thanks" }'
$ch = curl_init("https://telegramdownloadmanager.com/v1/invoices"); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "Authorization: Bearer " . getenv("PAYGATE_KEY"), "Content-Type: application/json", ], CURLOPT_POSTFIELDS => json_encode([ "amount" => 50000, "reference" => "order_77", "description" => "HSC Physics কোর্স", "success_url" => "https://shop.example/thanks", ]), ]); $invoice = json_decode(curl_exec($ch), true); header("Location: " . $invoice["checkout_url"]);
const r = await fetch("https://telegramdownloadmanager.com/v1/invoices", { method: "POST", headers: { Authorization: `Bearer ${process.env.PAYGATE_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ amount: 50000, reference: "order_77", description: "HSC Physics কোর্স", success_url: "https://shop.example/thanks", }), }); const invoice = await r.json(); res.redirect(invoice.checkout_url);
import os, requests r = requests.post("https://telegramdownloadmanager.com/v1/invoices", headers={"Authorization": f"Bearer {os.environ['PAYGATE_KEY']}"}, json={ "amount": 50000, "reference": "order_77", "description": "HSC Physics কোর্স", "success_url": "https://shop.example/thanks", }, timeout=10) invoice = r.json() return redirect(invoice["checkout_url"])
উত্তর
{
"id": "inv_7Qm2rT9cK1aB3dE5fG7h",
"object": "invoice",
"mode": "live",
"status": "pending",
"amount": 50000,
"currency": "BDT",
"reference": "order_77",
"description": "HSC Physics কোর্স",
"metadata": {},
"paid_amount": null,
"overpaid_amount": null,
"failure_code": null,
"checkout_url": "https://telegramdownloadmanager.com/pay/inv_7Qm2rT9cK1aB3dE5fG7h",
"telegram_url": "https://t.me/bikashchayanbikashbot?start=inv_7Qm2rT9cK1aB3dE5fG7h",
"success_url": "https://shop.example/thanks",
"cancel_url": null,
"expires_at": "2026-10-04T13:05:00+00:00",
"paid_at": null,
"created_at": "2026-10-04T12:05:00+00:00",
"payment": null
}পেমেন্ট হয়ে গেলে payment-এ থাকে provider, trx_id, sender, amount, received_at।
Invoice দেখা
একই আকারের invoice ফেরত দেয়। শুধু যে প্রজেক্টের key দিয়ে বানানো হয়েছিল, সেই key দিয়েই দেখা যায়।
TrxID জমা
নিজের পেমেন্ট ফর্ম বানালে ক্রেতার TrxID এখানে পাঠান। পেমেন্ট পেজ ব্যবহার করলে এটা লাগে না।
| ফিল্ড | মানে |
|---|---|
trx_idআবশ্যক | ক্রেতা যেমন পেয়েছে। ছোট হাতের অক্ষর, ফাঁকা জায়গা আর ড্যাশ নিজেই ঠিক করে নেওয়া হয় |
senderআবশ্যক | যে নম্বর থেকে টাকা পাঠানো হয়েছে। +880 থাকলেও চলে |
provider | bkash, nagad বা rocket। না দিলে সব মাধ্যমে খোঁজা হয় |
{
"result": "paid",
"message": "পেমেন্ট সফল! ৳500 পাওয়া গেছে।",
"invoice": { "status": "paid", ... }
}message ক্রেতাকে হুবহু দেখানোর মতো করে লেখা, আপনার সেটিংসের ভাষায়। সব result-এর তালিকা এখানে।
Invoice বাতিল
শুধু pending বা verifying invoice বাতিল করা যায়। invoice.cancelled webhook যায়।
ওয়ালেট
আপনার যে নম্বরগুলোর পেমেন্ট অটো যাচাই হয়। নিজের ফর্মে নম্বর দেখাতে এটা ব্যবহার করুন, তাহলে নম্বর বদলালে কোড বদলাতে হয় না।
{ "data": [ { "provider": "nagad", "msisdn": "01700000000", "kind": "personal" } ] }Webhook
ড্যাশবোর্ডে প্রজেক্টের Webhook URL দিন। প্রতিটা ঘটনায় সেখানে একটা POST যায়। ঠিকানা https:// হতে হবে, লোকাল বা প্রাইভেট IP নেওয়া হয় না।
| ঘটনা | কখন |
|---|---|
payment.succeeded | টাকা মিলেছে। বেশি এলে overpaid_amount-এ বাড়তি অংশ |
payment.underpaid | কম টাকা এসেছে, invoice বন্ধ। কত এসেছে paid_amount-এ |
payment.failed | দেওয়া TrxID-র পেমেন্ট নির্দিষ্ট সময়ের মধ্যে পাওয়া যায়নি। failure_code = not_found |
invoice.expired | মেয়াদ শেষ, টাকা আসেনি |
invoice.cancelled | আপনি বাতিল করেছেন |
ping | ড্যাশবোর্ডের "টেস্ট পাঠান" বাটন |
PayGate-Event-Id: evt_Zp4kQ8vN2mX7cR1tY6bW
PayGate-Signature: t=1791118932,v1=5d41402abc4b2a76b9719d911017c592...
Content-Type: application/json
{
"id": "evt_Zp4kQ8vN2mX7cR1tY6bW",
"type": "payment.succeeded",
"created": "2026-10-04T12:06:41+00:00",
"data": { /* পুরো invoice, payment সহ */ }
}- ২০০-২৯৯ ফেরত দিলে পাঠানো সফল ধরা হয়। না দিলে আবার পাঠানো হয়: ১ মিনিট, ৫ মিনিট, ৩০ মিনিট, ২ ঘণ্টা, ১২ ঘণ্টা পর।
- একই ঘটনা একাধিকবার আসতে পারে।
idদেখে একবারই কাজ করুন। - অর্ডার চালু করার আগে
data.status,data.amountআরdata.referenceনিজের ডাটাবেসের সাথে মিলিয়ে নিন।
সই যাচাই
ড্যাশবোর্ড থেকে Webhook secret (whsec_...) নিন। সই হলো HMAC-SHA256(secret, t + "." + raw_body), hex-এ। যে body এসেছে হুবহু সেটাই ব্যবহার করুন, JSON পার্স করে আবার বানাবেন না। ৫ মিনিটের বেশি পুরনো t বাতিল করুন।
$raw = file_get_contents("php://input"); parse_str(str_replace(",", "&", $_SERVER["HTTP_PAYGATE_SIGNATURE"] ?? ""), $sig); $expected = hash_hmac("sha256", ($sig["t"] ?? "") . "." . $raw, getenv("PAYGATE_WEBHOOK_SECRET")); if (!hash_equals($expected, $sig["v1"] ?? "") || abs(time() - (int)$sig["t"]) > 300) { http_response_code(401); exit; } $event = json_decode($raw, true); if ($event["type"] === "payment.succeeded") { // $event["data"]["reference"] → অর্ডার চালু করুন (একবারই) } http_response_code(200);
import crypto from "node:crypto"; // express.raw({ type: "application/json" }) দিয়ে raw body নিন app.post("/hooks/paygate", express.raw({ type: "application/json" }), (req, res) => { const sig = Object.fromEntries( (req.get("PayGate-Signature") || "").split(",").map(p => p.split("="))); const expected = crypto.createHmac("sha256", process.env.PAYGATE_WEBHOOK_SECRET) .update(`${sig.t}.`).update(req.body).digest("hex"); const ok = sig.v1 && sig.v1.length === expected.length && crypto.timingSafeEqual(Buffer.from(sig.v1), Buffer.from(expected)) && Math.abs(Date.now() / 1000 - Number(sig.t)) <= 300; if (!ok) return res.sendStatus(401); const event = JSON.parse(req.body); if (event.type === "payment.succeeded") { // event.data.reference → অর্ডার চালু করুন (একবারই) } res.sendStatus(200); });
import hashlib, hmac, os, time def verify(raw: bytes, header: str) -> bool: parts = dict(p.split("=", 1) for p in header.split(",") if "=" in p) t = parts.get("t", "0") expected = hmac.new(os.environ["PAYGATE_WEBHOOK_SECRET"].encode(), f"{t}.".encode() + raw, hashlib.sha256).hexdigest() return hmac.compare_digest(expected, parts.get("v1", "")) and abs(time.time() - int(t)) <= 300 # Flask @app.post("/hooks/paygate") def hook(): if not verify(request.get_data(), request.headers.get("PayGate-Signature", "")): return "", 401 event = request.get_json() if event["type"] == "payment.succeeded": ... # event["data"]["reference"] → অর্ডার চালু করুন (একবারই) return "", 200
অবস্থা ও ফলাফল
Invoice-এর status
pending | টাকার অপেক্ষায় |
verifying | TrxID দেওয়া হয়েছে, যাচাই চলছে |
paid | সফল। আর বদলায় না |
underpaid | কম টাকা, বন্ধ। আর বদলায় না |
expired | মেয়াদ শেষ |
cancelled | আপনি বাতিল করেছেন |
TrxID জমার result
paid | মিলেছে, সফল |
already_paid | এই invoice আগেই এই TrxID দিয়ে সফল হয়েছে |
verifying | এখনো নিশ্চিত হয়নি। হলে webhook যাবে |
underpaid | কম টাকা, invoice বন্ধ |
sender_mismatch | টাকা এই নম্বর থেকে আসেনি। আবার চেষ্টা করা যায় |
trx_already_used | TrxID অন্য পেমেন্টে ব্যবহার হয়ে গেছে |
bad_trx, bad_sender | লেখার ফরম্যাট ঠিক নেই |
too_many_attempts | এই invoice-এ অনেকবার ভুল, লক |
expired, cancelled | invoice আর খোলা নেই |
এরর
সব এরর একই আকারে আসে:
{ "error": { "code": "invalid_api_key" } }| HTTP | code |
|---|---|
| 401 | invalid_api_key: key ভুল, বাতিল, বা প্ল্যানের মেয়াদ শেষ |
| 404 | invoice_not_found |
| 400 | invalid_amount, invalid_ttl, invalid_return_url, invalid_provider, invoice_closed, metadata_too_large, unsupported_currency |
| 422 | invalid_request: fields-এ কোন ফিল্ড ঠিক নেই |
| 429 | rate_limited: প্রতি key মিনিটে ৬০০ রিকোয়েস্ট |
টেস্ট মোড
sk_test_ key দিয়ে বানানো invoice শুধু টেস্ট পেমেন্ট দিয়ে মেলে, আসল টাকা দিয়ে কখনো না। উল্টোটাও সত্যি।
- ড্যাশবোর্ডের ফোন পাতার টেস্ট অংশ থেকে একটা টেস্ট পেমেন্ট তৈরি করুন।
sk_test_key দিয়ে invoice বানান, পেমেন্ট পেজে ওই TrxID আর নম্বর দিন।- পেজে
TESTচিহ্ন দেখাবে। webhook-এdata.modeহবেtest। আসল অর্ডার চালু করার কোডে এটা অবশ্যই দেখবেন।