নাগরিক দল, গবেষক ও পার্টনার অ্যাপের জন্য কী-ভিত্তিক, সংস্করণযুক্ত REST এপিআই। এটি একটি স্বাধীন কমিউনিটি প্রকল্প, সরকারি ইন্টারফেস নয়।
ভূমিকা
নাগরিকদের জানানো সমস্যার তথ্যের মূল ভান্ডার হলো জানাও। টিকিট সিস্টেম, ড্যাশবোর্ড বা ওয়ার্ড অফিসের সফটওয়্যার এখান থেকে পড়ে এবং এখানেই স্ট্যাটাস ফেরত লেখে, আলাদা পুরনো হয়ে যাওয়া কপি রাখে না।
সব এন্ডপয়েন্ট /api/v1 এর অধীনে। উত্তর JSON। OpenAPI বিবরণ পাওয়া যায় /api/v1/openapi.json এ।
দ্রুত শুরু
কী পেলে একটি কলেই সাম্প্রতিক সমস্যাগুলির তালিকা পাবেন। প্লেসহোল্ডারের জায়গায় নিজের কী বসান এবং ক্লায়েন্ট-সাইড কোডে রাখবেন না।
প্রতিটি অনুরোধে কী-টি বিয়ারার টোকেন হিসেবে পাঠান। কী jnk_ দিয়ে শুরু হয় এবং জানাও অ্যাডমিন অ্যাডমিন এলাকার ইন্টিগ্রেশন অংশে তৈরি করেন। কী নির্দিষ্ট ওয়ার্ড বা বিভাগে সীমিত করা যায়।
HTTP header
Authorization: Bearer jnk_YOUR_KEY
স্কোপ
issues:readসমস্যা, আপডেট, ওয়ার্ড ও ইভেন্ট ফিড পড়া।
stats:readসামগ্রিক পরিসংখ্যান পড়া।
issues:writeনিজের সিস্টেম থেকে সমস্যা তৈরি করা।
issues:updateকী-এর সীমার মধ্যে সমস্যার স্ট্যাটাস বদলানো।
ত্রুটি
সব ত্রুটির গঠন একই। 401 মানে কী নেই বা ভুল, 403 মানে স্কোপ নেই বা সমস্যাটি কী-এর ওয়ার্ডের বাইরে, 404 মানে পাওয়া যায়নি, 429 মানে খুব দ্রুত অনুরোধ পাঠানো হচ্ছে।
একটি সমস্যার প্রকাশ্য অগ্রগতির আপডেট, পুরনো থেকে নতুন।
স্কোপ: issues:read
GET/api/v1/issues/{id}/comments
একটি ইস্যুর প্রকাশ্য মন্তব্য, পুরোনো আগে। প্রতিটি মন্তব্যে body ও is_official (স্কোপের কর্মীর উত্তর) থাকে। লেখকের কোনো ক্ষেত্র নেই।
স্কোপ: issues:read
GET/api/v1/wards
যেসব ওয়ার্ডে সমস্যা জানানো যায় তার তালিকা।
স্কোপ: issues:read
GET/api/v1/stats
স্ট্যাটাস, বিভাগ ও ওয়ার্ড অনুযায়ী সামগ্রিক সংখ্যা।
স্কোপ: stats:read
GET/api/v1/events?after=&limit=
পরিবর্তনের ফিড। দেওয়া cursor-এর পরের ইভেন্ট দেয়: issue.created, issue.status_changed, issue.update_added ও issue.merged (ডুপ্লিকেট অন্য অভিযোগে মেলানো হয়েছে; data.merged_into হলো মূল অভিযোগ)। রিপোর্টকারী জানালে যে সারানো ইস্যু অসম্পূর্ণ এবং সেটি আবার কাজ চলছে অবস্থায় ফিরলে issue.reopened পাঠানো হয়।
সমস্যা তৈরি করুন। title, description, category, ward_id, lat, lng ও external_ref পাঠান। external_ref-এ আইডেম্পোটেন্ট: একই অনুরোধ আবার পাঠালে নকল না হয়ে আগের সমস্যাটি ফেরত আসে। এভাবে তৈরি সমস্যায় কোনো ব্যক্তিগত তথ্য রাখা হয় না।
ঐচ্ছিক নোটসহ সমস্যার স্ট্যাটাস বদলান। শুধু কী-এর সীমার মধ্যে কাজ করে। কী কখনও confirmed দিতে পারে না: ঠিক হয়েছে কিনা শুধু মূল রিপোর্টারই নিশ্চিত করতে পারেন।
তালিকার এন্ডপয়েন্ট next_cursor ফেরত দেয়। পরের পেজের জন্য সেটি cursor হিসেবে পাঠান; এটি null হলে শেষ। কার্সরকে অস্বচ্ছ স্ট্রিং ধরুন।
ওয়েবহুক ছাড়া সিঙ্কে থাকতে ইভেন্ট ফিড পোল করুন। শেষ প্রক্রিয়া করা cursor জমা রাখুন, তার পরের ইভেন্ট চান, প্রতিটি সামলান, তারপর নতুন cursor সংরক্ষণ করুন। কিছু না এলে পোলের ব্যবধান বাড়ান।
curl
# Poll the change feed, resuming from the last saved cursor
curl -H "Authorization: Bearer jnk_YOUR_KEY" \
"https://YOUR_JAANAO_HOST/api/v1/events?after=LAST_CURSOR&limit=100"
ওয়েবহুক দ্রুততর, তবে মিস হওয়া ডেলিভারির জন্য পোলিং ভালো বিকল্প।
ওয়েবহুক
অ্যাডমিনের মাধ্যমে একটি এন্ডপয়েন্ট নিবন্ধন করুন, ইভেন্ট JSON POST হিসেবে পাবেন: issue.created, issue.status_changed, issue.update_added ও issue.merged (ডুপ্লিকেট অন্য অভিযোগে মেলানো হয়েছে; data.merged_into হলো মূল অভিযোগ)। রিপোর্টকারী জানালে যে সারানো ইস্যু অসম্পূর্ণ এবং সেটি আবার কাজ চলছে অবস্থায় ফিরলে issue.reopened পাঠানো হয়।
হেডার
X-Jaanao-Eventইভেন্টের নাম, যেমন issue.status_changed।
X-Jaanao-Deliveryএই ডেলিভারির অনন্য আইডি। নকল বাদ দিতে ব্যবহার করুন।
X-Jaanao-Timestampডেলিভারি সাইন করার ইউনিক্স সময় (সেকেন্ড)।
X-Jaanao-Signatureসময়, একটি বিন্দু এবং মূল বডি জুড়ে এন্ডপয়েন্টের সিক্রেট দিয়ে করা HMAC-SHA256 (হেক্স)।
পার্স করার আগে মূল রিকোয়েস্ট বডির সঙ্গে স্বাক্ষর মেলান। রিপ্লে ঠেকাতে ৫ মিনিটের চেয়ে পুরনো টাইমস্ট্যাম্প বাতিল করুন। ব্যর্থ ডেলিভারি ক্রমবর্ধমান বিরতিতে আবার চেষ্টা হয়, তাই দ্রুত 2xx দিন এবং পরে ইভেন্ট প্রক্রিয়া করুন।
Node.js
import crypto from "node:crypto";
// rawBody must be the exact request body string, before JSON.parse.
export function verify(rawBody, headers, secret) {
const timestamp = headers["x-jaanao-timestamp"];
const signature = headers["x-jaanao-signature"];
const age = Math.abs(Date.now() / 1000 - Number(timestamp));
if (!timestamp || !signature || age > 300) return false; // older than 5 minutes
const expected = crypto
.createHmac("sha256", secret)
.update(timestamp + "." + rawBody)
.digest("hex");
const a = Buffer.from(expected);
const b = Buffer.from(signature);
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
সমস্যা এই ধাপগুলো পেরিয়ে এগোয়। ইন্টিগ্রেশন seen, in_progress, fixed ও closed দিতে পারে। confirmed শুধু যিনি জানিয়েছেন তিনিই দিতে পারেন।
জানানো হয়েছেreported↓→
কাজ চলছেin_progress↓→
ঠিক হয়েছেfixed↓→
নিশ্চিতconfirmedশুধু রিপোর্টার↓→
বন্ধclosed
রেট লিমিট
প্রতিটি কী-এর জন্য আলাদা সীমা প্রযোজ্য। সীমা ছাড়ালে এপিআই 429 দেয়, সঙ্গে Retry-After হেডারে কত সেকেন্ড অপেক্ষা করতে হবে তা থাকে। ঘন ঘন পুরো তালিকা না টেনে ইভেন্ট ফিড বা ওয়েবহুক ব্যবহার করুন।
গোপনীয়তার নিশ্চয়তা
রিপোর্ট বেনামি হোক বা না হোক, এপিআই কখনও রিপোর্টারের পরিচয় বা ফোন নম্বর ফেরত দেয় না।
কোনো উত্তর, ইভেন্ট বা ওয়েবহুকে নাম, ফোন নম্বর বা অ্যাকাউন্ট আইডি থাকে না।
এপিআই দিয়ে তৈরি সমস্যায় কোনো ব্যক্তিগত তথ্য রাখা হয় না।
অবস্থান মানে রিপোর্টারের বসানো পিন, ব্যক্তিগত ঠিকানা নয়।
কী নির্দিষ্ট ওয়ার্ড বা বিভাগে সীমিত করা যায়, ফলে পার্টনার শুধু প্রয়োজনীয় তথ্যই দেখে।
কী চান
কী দেন জানাও অ্যাডমিন। চাইতে হলে জানান আপনি কে, কী বানাচ্ছেন, কোন স্কোপ লাগবে এবং কোন ওয়ার্ড জুড়ে কাজ।
কী চাওয়ার যোগাযোগের তথ্য এখানে প্রকাশ করা হবে। ততদিন যে মাধ্যমে জানাও দলের সঙ্গে কথা বলেন সেটিতেই জানান।