লগইনরেজিস্টার

API ডকুমেন্টেশন

Base URL: https://epay.nagad.top/api/v1 · সব রিকোয়েস্ট ও রেসপন্স JSON · অ্যামাউন্ট BDT (টাকা), যেমন "500" বা "499.50"।

অথেনটিকেশন

ড্যাশবোর্ডের API ও ওয়েবহুক পেজ থেকে key নিন (cpk_…) এবং প্রতি রিকোয়েস্টে পাঠান:

Authorization: Bearer cpk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Key কেবল সার্ভার-সাইডে ব্যবহার করুন।

১. পেমেন্ট তৈরি

POST /api/v1/payments

ফিল্ডবিবরণ
amount *পরিমাণ (কমপক্ষে 1.00)
order_idআপনার সিস্টেমের অর্ডার নম্বর
descriptionচেকআউটে দেখানো বিবরণ
customer_name / customer_email / customer_phoneগ্রাহকের তথ্য
success_url / cancel_urlপেমেন্ট শেষে গ্রাহক যেখানে ফিরবে (?payment_id=&order_id=&status= যুক্ত হয়ে)
webhook_urlএই পেমেন্টের জন্য আলাদা ওয়েবহুক URL (ঐচ্ছিক)
expires_inমিনিটে মেয়াদ, ৫–১৪৪০ (ডিফল্ট ৩০)
metadataআপনার নিজস্ব JSON অবজেক্ট (সর্বোচ্চ ২ কেবি)
Header Idempotency-Keyএকই কী দিয়ে আবার কল করলে নতুন পেমেন্ট না হয়ে আগেরটি ফেরত আসে
curl -X POST https://epay.nagad.top/api/v1/payments \
  -H "Authorization: Bearer cpk_..." \
  -H "Content-Type: application/json" \
  -d '{"amount":"500","order_id":"INV-1001","description":"Premium plan",
       "success_url":"https://yoursite.com/thanks","cancel_url":"https://yoursite.com/cart",
       "customer_phone":"01700000000"}'

রেসপন্স 201:

{
  "id": "pay_9f2c4e8a1b7d3c6f0a5e2d41",
  "order_id": "INV-1001",
  "status": "pending",
  "amount": "500.00",
  "currency": "BDT",
  "pay_url": "https://epay.nagad.top/pay.php?id=pay_9f2c4e8a1b7d3c6f0a5e2d41",
  "expires_at": "2026-10-19 12:00:00",
  ...
}

গ্রাহককে pay_url-এ রিডাইরেক্ট করুন।

২. পেমেন্ট দেখা / তালিকা / বাতিল

GET  /api/v1/payments/{id}
GET  /api/v1/payments?status=paid&limit=20&order_id=INV-1001
POST /api/v1/payments/{id}/cancel

status: pending · paid · expired · cancelled

৩. ওয়েবহুক

পেমেন্টের অবস্থা বদলালে আপনার Webhook URL-এ POST যায়। ইভেন্ট: payment.succeeded, payment.expired, payment.cancelled। আপনার সার্ভার 2xx দিলে সফল; নইলে ১ মি, ৫ মি, ৩০ মি, ২ ঘণ্টা, ৬ ঘণ্টা, ১২ ঘণ্টা, ২৪ ঘণ্টা পরে আবার চেষ্টা হয় (মোট ৮ বার)।

POST /your-webhook
X-EPAY-Event: payment.succeeded
X-EPAY-Signature: t=1760851200,v1=5b1c…(hex HMAC-SHA256)

{"event":"payment.succeeded","created_at":"2026-10-19 11:30:02",
 "data":{"id":"pay_…","order_id":"INV-1001","status":"paid","amount":"500.00",
         "received_amount":"500.00","method":"bKash","trx_id":"8N7A6D5E4C", ...}}

সিগনেচার যাচাই করুন (সিক্রেট ড্যাশবোর্ডে পাবেন): HMAC_SHA256(secret, t + "." + rawBody) — এবং t ৫ মিনিটের বেশি পুরোনো হলে বাতিল করুন। একই ইভেন্ট একাধিকবার আসতে পারে, তাই অর্ডার আপডেট idempotent রাখুন।

PHP

$raw = file_get_contents("php://input");
parse_str(str_replace(",", "&", $_SERVER["HTTP_X_EPAY_SIGNATURE"] ?? ""), $s);   // t, v1
$ok = isset($s["t"], $s["v1"]) && abs(time() - (int)$s["t"]) < 300
   && hash_equals(hash_hmac("sha256", $s["t"] . "." . $raw, $WEBHOOK_SECRET), $s["v1"]);
if (!$ok) { http_response_code(400); exit; }
$e = json_decode($raw, true);
if ($e["event"] === "payment.succeeded") { /* অর্ডার পেইড করুন: $e["data"]["order_id"] */ }
http_response_code(200);

Node.js (Express)

const crypto = require("crypto");
app.post("/cp-webhook", express.raw({type: "application/json"}), (req, res) => {
  const [t, v1] = req.get("X-EPAY-Signature").split(",").map(x => x.split("=")[1]);
  const mac = crypto.createHmac("sha256", process.env.CP_SECRET).update(t + "." + req.body).digest("hex");
  if (Math.abs(Date.now()/1000 - t) > 300 || !crypto.timingSafeEqual(Buffer.from(mac), Buffer.from(v1))) return res.sendStatus(400);
  const e = JSON.parse(req.body);
  // handle e.event / e.data
  res.sendStatus(200);
});

Python (Flask)

import hmac, hashlib, time, json
@app.post("/cp-webhook")
def hook():
    raw = request.get_data()
    p = dict(x.split("=", 1) for x in request.headers["X-EPAY-Signature"].split(","))
    mac = hmac.new(SECRET.encode(), (p["t"] + ".").encode() + raw, hashlib.sha256).hexdigest()
    if abs(time.time() - int(p["t"])) > 300 or not hmac.compare_digest(mac, p["v1"]): return "", 400
    e = json.loads(raw)
    return "", 200

৪. সম্পূর্ণ ফ্লো (সংক্ষেপে)

  1. আপনার সার্ভার → POST /payments → pay_url
  2. গ্রাহককে pay_url-এ পাঠান; সে নম্বরে টাকা পাঠিয়ে TrxID দেয়
  3. SMS মিললে ওয়েবহুক payment.succeeded আসে
  4. গ্রাহক success_url-এ ফেরে — শুধু এই রিডাইরেক্টের ভরসায় অর্ডার দেবেন না; ওয়েবহুক বা GET /payments/{id} দিয়ে নিশ্চিত হোন

এরর

{"error":{"type":"invalid_amount","message":"..."}}

401 key ভুল · 404 পাওয়া যায়নি · 409 অবস্থা/সেটআপ সমস্যা · 422 ইনপুট ভুল · 429 রেট-লিমিট