মূল অংশে যান
কুইজঝড়

ডেভেলপার

দুটো পথ: এমবেড (চাবি লাগে না, সব প্ল্যানে) আর REST API (ইনস্টিটিউশন/প্রিমিয়াম প্ল্যানে)।

১) এমবেড — কপি-পেস্ট, ফ্রি

যেকোনো ওয়েবসাইট, WordPress, Google Sites বা LMS-এ বসান। হোস্ট-পাতার শেয়ার-বারে "এমবেড" বোতাম চাপলেই কোডটা কপি হয়ে যায়।

জয়েন-কার্ড (PIN দিয়ে ঢোকা)
<iframe src="https://quizjhor.com/embed/join?pin=482013&lang=bn"
        width="100%" height="380" style="border:0;border-radius:16px"
        title="QuizJhor" loading="lazy"></iframe>
ফলাফল তালিকা
<iframe src="https://quizjhor.com/embed/m/<token>?lang=bn"
        width="100%" height="520" style="border:0;border-radius:16px"
        title="QuizJhor results" loading="lazy"></iframe>
খেলা ফ্রেমের ভেতরেই (নতুন)
<iframe src="https://quizjhor.com/play?pin=482013&lang=bn"
        width="100%" height="720" style="border:0;border-radius:16px"
        title="QuizJhor" allow="autoplay; fullscreen" loading="lazy"></iframe>
  • • জয়েন-কার্ডে খেলা নতুন ট্যাবে খোলে; আর উপরের /play এমবেডে খেলা ফ্রেমের ভেতরেই চলে — লম্বা ফ্রেম (কমপক্ষে 640px) আর `allow="autoplay; fullscreen"` দিন।
  • • কিছু ব্রাউজার (পুরনো Safari, লকডাউন-মোড) এমবেড-করা পাতার স্টোরেজ বন্ধ রাখে — তখন পাতাটা নিজেই "নতুন ট্যাবে খেলুন" বোতাম দেখায়, ছাত্র মাঝপথে আটকায় না।
  • • `lang=bn` বা `lang=en` — আপনি যে ভাষায় কোড কপি করবেন, দর্শক সেটাই দেখবে।
  • • আপনার LMS যদি `sandbox` অ্যাট্রিবিউট ব্যবহার করে, তাতে `allow-same-origin allow-scripts allow-popups` রাখুন — `allow-same-origin` ছাড়া ব্রাউজার পাতাটিকে স্টোরেজ-বিহীন "opaque" করে দেয়, খেলা চালানোই যায় না।
  • • "Powered by কুইজঝড়" লেখাটা white-label প্ল্যানে থাকে না।

২) REST API

ওয়ার্কস্পেসের মালিক ড্যাশবোর্ড → ডেভেলপার থেকে চাবি বানাবেন। চাবিটা একবারই দেখানো হয়।

curl -H "Authorization: Bearer qj_live_..." \
     -H "X-API-Version: 1" \
     https://quizjhor.com/api/v1/me
এন্ডপয়েন্টকী দেয়
GET /api/v1/meচাবি ও ওয়ার্কস্পেস যাচাই — প্রথম কলেই সব গেট প্রমাণ হয়
GET /api/v1/quizzesকুইজ-তালিকা (শিরোনাম, বিষয়, প্রশ্ন-সংখ্যা)
GET /api/v1/gamesসেশন-তালিকা; `?since=` দিয়ে ইনক্রিমেন্টাল সিঙ্ক
GET /api/v1/games/:id/resultsএক সেশনের ফল — নাম, নম্বর, র‍্যাংক, পার্সেন্টাইল
POST /api/v1/gamesনতুন সেশন চালু (write-চাবি লাগে) — ফেরত দেয় PIN, joinUrl, embedUrl

নিয়ম

  • • ?limit= — ডিফল্ট 50, সর্বোচ্চ 100।
  • • চলমান সেশনে `results` হয় `null` — পরীক্ষা শেষ না হওয়া পর্যন্ত ফল দেওয়া হয় না।
  • • চাবি যে ওয়ার্কস্পেসের, শুধু তারই ডেটা পড়া যায়; অন্যের আইডি দিলে ৪০৪।
  • • অভিভাবকের ফোন, রোল-নম্বর বা সনদ-কোড API-তে কখনো যায় না।
  • • রেসপন্স-হেডারে সার্ভারের API-ভার্সন থাকে; নতুন ফিল্ড যোগ হতে পারে, পুরনো ফিল্ডের নাম বদলায় না।
  • • চাবি ডিফল্টে শুধু পড়তে পারে। সেশন তৈরি করতে চাবি বানানোর সময় "গেম তৈরির অনুমতি" চালু করুন।
  • • সেশন তৈরিতে ওয়েবের সব নিয়মই খাটে — প্ল্যান-সীমা, কুইজে প্রশ্ন থাকা, খালি প্রশ্ন না থাকা। একই কুইজে চলমান গেম থাকলে নতুন PIN না বানিয়ে সেটাই ফেরত আসে।

এররগুলো

  • • 401 — চাবি নেই, ভুল, বা বাতিল করা।
  • • 403 — চাবি ঠিক আছে কিন্তু প্ল্যানে API নেই, ওয়ার্কস্পেস স্থগিত, বা scope নেই।
  • • 409 — সেশন তৈরিতে: ওয়ার্কস্পেসে কোনো হোস্ট নেই।
  • • 429 — খুব দ্রুত অনুরোধ — একটু ধীরে।

৩) Webhook — ফল আপনা-আপনি

ড্যাশবোর্ড → ডেভেলপার-এ আপনার https ঠিকানা দিন। পরীক্ষা শেষ হলেই আমরা POST করব — বারবার API কল করার দরকার নেই।

POST <your-url>
X-QJ-Event: game.ended
X-QJ-Timestamp: 1730000000000
X-QJ-Signature: <hex>

{"event":"game.ended","deliveryId":"...","game":{...},"results":[...]}
স্বাক্ষর যাচাই
const expected = crypto.createHmac("sha256", secret)
  .update(timestamp + "." + rawBody).digest("hex");
// crypto.timingSafeEqual(expected, headerSignature)
  • • ২০০-রেঞ্জ উত্তর না পেলে ৫ বার পর্যন্ত আবার চেষ্টা হয়, তারপর ব্যর্থ হিসেবে দেখানো হয়।
  • • এক সেশনের এক ইভেন্ট একবারই পাঠানো হয় (deliveryId দিয়ে মিলিয়ে নিতে পারেন)।
  • • URL বদলালে নতুন সিক্রেট তৈরি হয়; পুরনো সিক্রেট আর বৈধ নয়।