API v1
ডেভেলপার ডকুমেন্টেশন
একটা POST দিয়ে পেমেন্ট বানান, কাস্টমারকে চেকআউটে পাঠান, ওয়েবহুকে ফলাফল নিন। সিক্রেট কী কখনো ব্রাউজার বা মোবাইল অ্যাপে রাখবেন না।
অথেন্টিকেশন
ড্যাশবোর্ড → ডেভেলপার থেকে কী নিন। প্রতিটা রিকোয়েস্টে Authorization: Bearer <secret key> হেডার দিন। বেস URL:
https://oxypay.lovable.app/api/public/v1টেস্ট মোড
oxp_test_sk_ দিয়ে শুরু হওয়া কী দিয়ে বানানো পেমেন্টে আসল টাকা লাগে না। চেকআউট পেজে "সফল" বা "ব্যর্থ" বাটন থাকে, চাপলেই পেমেন্টের অবস্থা বদলায় আর আপনার টেস্ট ওয়েবহুকে খবর যায়। উত্তরে livemode: false থাকে। টেস্ট আর লাইভ পেমেন্ট কখনো মেশে না।
পেমেন্ট তৈরি
একই order_id আবার পাঠালে আগের পেমেন্টটাই ফেরত আসে (200)।
curl -X POST https://oxypay.lovable.app/api/public/v1/payments \
-H "Authorization: Bearer oxp_test_sk_..." \
-H "Idempotency-Key: order-1042-try1" \
-H "Content-Type: application/json" \
-d '{
"amount": 2450,
"order_id": "1042",
"description": "Order #1042",
"return_url": "https://shop.example.bd/orders/1042"
}'
# 201 Created
{
"payment_id": "6f1c…",
"order_id": "1042",
"amount": 2450,
"currency": "BDT",
"status": "pending",
"verified": false,
"livemode": false,
"checkout_url": "https://oxypay.lovable.app/pay/ab12cd34ef",
"expires_at": "…"
}Idempotency-Key
নেটওয়ার্ক কেটে গেলে নিশ্চিন্তে আবার পাঠাতে Idempotency-Key হেডার দিন। ২৪ ঘণ্টার মধ্যে একই কী আর একই বডি একই পেমেন্ট ফেরত দেয় (Idempotent-Replayed: true হেডার সহ)। একই কী অন্য বডিতে দিলে 409 idempotency_conflict।
রিকোয়েস্ট সাইন করা
প্রতিটা কী-র সাথে একটা সাইনিং সিক্রেট পাবেন। সাইন করা ঐচ্ছিক; ড্যাশবোর্ডে "শুধু সাইন করা" চালু করলে সাইন ছাড়া রিকোয়েস্ট 401 signature_required পাবে। টাইমস্ট্যাম্প ৫ মিনিটের বেশি আগে-পরে হলে বাতিল।
OxyPay-Signature: v1=hex(HMAC-SHA256(signing_secret, "{ts}.{METHOD}.{path}.{rawBody}"))// Node.js — sign a request (optional, or required if you turn on "Signed only")
import crypto from "node:crypto";
const ts = Math.floor(Date.now() / 1000);
const body = JSON.stringify({ amount: 2450, order_id: "1042" });
const toSign = `${ts}.POST./api/public/v1/payments.${body}`; // GET: `${ts}.GET./api/public/v1/payments/1042.`
const sig = crypto.createHmac("sha256", process.env.OXYPAY_SIGNING_SECRET).update(toSign).digest("hex");
await fetch("https://oxypay.lovable.app/api/public/v1/payments", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.OXYPAY_SECRET_KEY}`,
"Content-Type": "application/json",
"OxyPay-Timestamp": String(ts),
"OxyPay-Signature": "v1=" + sig,
},
body, // send exactly the bytes you signed
});ওয়েবহুক
ড্যাশবোর্ড → ওয়েবহুক-এ https ঠিকানা দিন। পেমেন্টের অবস্থা বদলালেই আমরা POST পাঠাই। ১০ সেকেন্ডের মধ্যে 2xx না পেলে আবার পাঠাই (5m, 15m, 30m, 1h, 3h, 6h, 12h পরে, মোট 8 বার)। একই id দুবার এলে একবারই কাজ করুন।
payment.under_reviewpayment.succeededpayment.failedpayment.refundedpayment.partially_refundedpayment.cancelledpayment.expiredwebhook.testহেডার: OxyPay-Event-Id, OxyPay-Event-Type, OxyPay-Timestamp, OxyPay-Signature: v1=hex(HMAC-SHA256(webhook_secret, "{ts}.{rawBody}"))
// Node.js (Express) — verify an OxyPay webhook
import crypto from "node:crypto";
app.post("/oxypay/webhook", express.raw({ type: "application/json" }), (req, res) => {
const ts = req.get("OxyPay-Timestamp");
const expected = "v1=" + crypto
.createHmac("sha256", process.env.OXYPAY_WEBHOOK_SECRET)
.update(`${ts}.${req.body.toString()}`)
.digest("hex");
const given = req.get("OxyPay-Signature") ?? "";
const ok = given.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(given), Buffer.from(expected)) &&
Math.abs(Date.now() / 1000 - Number(ts)) < 300;
if (!ok) return res.sendStatus(400);
const event = JSON.parse(req.body); // { id, type, livemode, data: { order_id, status, verified, ... } }
if (alreadyProcessed(event.id)) return res.sendStatus(200);
if (event.type === "payment.succeeded" && event.data.verified) confirmOrder(event.data.order_id);
res.sendStatus(200);
});পেমেন্টের অবস্থা
শুধু status "success" আর verified true হলে অর্ডার কনফার্ম করুন। নিচের পথের বাইরে অবস্থা বদলানো যায় না — ডেটাবেস নিজেই আটকায়।
created→pendingverifyingunder_reviewfailedexpiredcancelledpending→verifyingunder_reviewsuccessfailedexpiredcancelledverifying→under_reviewsuccessfailedunder_review→verifyingsuccessfailedsuccess→refundedpartially_refundedpartially_refunded→refundedfailed→শেষ অবস্থাexpired→শেষ অবস্থাcancelled→শেষ অবস্থাrefunded→শেষ অবস্থাসীমা আর এরর
প্রতি কী-তে মিনিটে ১২০টা রিকোয়েস্ট। উত্তরে X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset হেডার থাকে; সীমা পেরোলে 429 আর Retry-After।
এন্ডপয়েন্ট
/paymentsপেমেন্ট তৈরি (চেকআউট লিংক পাবেন)/payments/{payment_id | order_id}পেমেন্টের অবস্থা/openapi.jsonOpenAPI স্পেক/device/pairফোন অ্যাপ যুক্ত করা (QR কোড)/device/eventsফোন থেকে টাকা আসার SMS