ড্যাশবোর্ডে ওয়েবহুক সেট আপ করুন, ডেলিভারি গ্রহণ করুন আর HMAC সিগনেচার যাচাই করুন – curl, Node.js আর PHP-এর উদাহরণসহ।
আপনার ওয়ার্কস্পেসে কিছু ঘটলেই ওয়েবহুক আপনার সার্ভারে একটি HTTP রিকোয়েস্ট পাঠায় – যেমন কোনো পেজ পাবলিশ হলে। ফলে কিছু বদলেছে কি না তা আপনাকে বারবার জিজ্ঞাসা করতে হয় না। প্রতিটি ডেলিভারি সাইন করা থাকে, যাতে আপনার সার্ভার আসল বার্তা আর জাল বার্তা আলাদা করতে পারে।
যা দরকার
- ওয়ার্কস্পেসে মালিক বা অ্যাডমিন হওয়া – “ওয়েবহুক” মেনু আইটেম শুধু এই রোলগুলোর জন্যই দেখা যায়
- Creator Pro থেকে; Creator Free-তে লেখা থাকে “ওয়েবহুক Creator Pro থেকে পাওয়া যায়।”
- Creator Pro-তে সর্বোচ্চ ৫টি ওয়েবহুক, Creator Agency-তে ২৫টি, Enterprise-এ ১০০টি (পরিবর্তনযোগ্য)
- একটি সার্ভার, যেটিতে পাবলিক https ঠিকানায় পৌঁছানো যায়
ওয়েবহুক আপনি শুধু ড্যাশবোর্ডে পরিচালনা করেন। API কী দিয়ে এগুলো তৈরি বা পরিবর্তন করা যায় না।
ওয়েবহুক তৈরি করুন
- নেভিগেশনে “ওয়েবহুক” খুলুন
- “+ নতুন ওয়েবহুক”-এ ক্লিক করুন
- টার্গেট URL দিন আর ইভেন্টগুলো বেছে নিন
- ঐচ্ছিক: একটি বিবরণ দিন আর স্ট্যাটাস বেছে নিন
- “ওয়েবহুক তৈরি করুন”-এ ক্লিক করুন
- “সম্পন্ন” ধাপে সাইনিং সিক্রেট (“সাইনিং সিক্রেট — শুধু এখনই দেখা যাচ্ছে”) কপি করে আপনার সার্ভারে রাখুন – এটি শুধু এখনই দেখানো হয়
- “টেস্ট” দিয়ে ওয়েবহুকটি পরীক্ষা করুন। ফলাফল পরের টেস্ট পর্যন্ত কার্ডে থাকে: “সফলভাবে পৌঁছেছে” বা HTTP কোডসহ “পৌঁছায়নি” (অথবা “কোনো উত্তর নেই”), সময়কাল আর রেসপন্সের শুরুর অংশ
- “গন্তব্য URL (https://…)”
- সর্বোচ্চ ২০৪৮ অক্ষর। শুধু https, URL-এ কোনো ক্রেডেনশিয়াল নয়, কোনো localhost ঠিকানা নয় আর .local, .internal বা .lan-এর মতো অভ্যন্তরীণ নাম নয়। নামটি অবশ্যই পাবলিক IP ঠিকানায় নির্দেশ করবে; প্রতিটি ডেলিভারির আগে LinkHarbor এটি আবার যাচাই করে।
- “ইভেন্ট”
- অন্তত একটি ইভেন্ট। প্রতিটি গ্রুপে “সব বেছে নিন” আর “সব বাদ দিন” আছে।
- “বিবরণ”
- ঐচ্ছিক, সর্বোচ্চ ২৫৫ অক্ষর – যেমন ওয়েবহুকটি কীসের জন্য।
- “স্ট্যাটাস”
- “সক্রিয়” বা “নিষ্ক্রিয়”। নিষ্ক্রিয় ওয়েবহুক কোনো ডেলিভারি পায় না।
ইভেন্ট
| ইভেন্ট | ড্যাশবোর্ডে | কখন | data-এর বিষয়বস্তু |
|---|---|---|---|
| page.published | পেজ প্রকাশিত হয়েছে | একটি পেজ পাবলিশ হয়েছে – ড্যাশবোর্ডে, API দিয়ে বা কোনো AI অ্যাসিস্ট্যান্টের মাধ্যমে | page_id, version, checksum, published_by_user_id (API কী আর AI অ্যাসিস্ট্যান্টের ক্ষেত্রে null) |
| form.submitted | ফর্ম জমা হয়েছে | কোনো ভিজিটর আপনার একটি পেজে ফর্ম জমা দিয়েছেন | form_id, form_name, submission_id, page_id, block_id, submitted_at, values (ফিল্ড কী → মান), consent (সম্মতির কী → true/false) |
| domain.verified | ডোমেইন যাচাই হয়েছে | একটি কাস্টম ডোমেইন সফলভাবে যাচাই হয়েছে | domain_id, hostname, verification_method, status |
| domain.disabled | ডোমেইন নিষ্ক্রিয় হয়েছে | ড্যাশবোর্ডে একটি কাস্টম ডোমেইন নিষ্ক্রিয় করা হয়েছে (ডাউনগ্রেডের সময় নয়) | domain_id, hostname, status |
| webhook.test | – (“টেস্ট” বাটন) | আপনি “টেস্ট”-এ ক্লিক করেন | message (টেস্ট শুরু করা ব্যক্তির অ্যাকাউন্টের ভাষায় একটি নোট; এর ওপর নির্ভর করবেন না) |
form.submitted-এ মানগুলো ঠিক ভিজিটর যেভাবে জমা দিয়েছেন সেভাবেই থাকে, কিন্তু কখনো তাঁর IP ঠিকানা বা ব্রাউজার থাকে না। ডেলিভারি ব্যাকগ্রাউন্ডে চলে: ভিজিটরকে এর জন্য অপেক্ষা করতে হয় না, আর ডেলিভারি ব্যর্থ হলেও সাবমিশন আটকায় না।
একটি ডেলিভারির গঠন
LinkHarbor প্রতিটি ডেলিভারি JSON বডি আর এই হেডারগুলোসহ একটি POST হিসেবে পাঠায়:
| হেডার | বিষয়বস্তু |
|---|---|
| Content-Type | application/json |
| X-LinkHarbor-Event | ইভেন্টের নাম, যেমন page.published |
| X-LinkHarbor-Delivery-Id | এই ডেলিভারির অনন্য আইডি (UUID), বডির id-এর সাথে অভিন্ন |
| X-LinkHarbor-Timestamp | পাঠানোর সময়, Unix সেকেন্ডে |
| X-LinkHarbor-Signature | sha256= আর তারপর hex-এ HMAC-SHA256 সিগনেচার |
| X-LinkHarbor-Signature-Version | v1 |
{
"id": "3f1c2a9e-8d4b-4a51-9f0e-6b7c1d2e3f40",
"event": "page.published",
"created_at": "2026-11-01T09:30:12+00:00",
"data": {
"page_id": 42,
"version": 8,
"checksum": "9b1e5c…",
"published_by_user_id": 7
}
} পুনরায় পাঠানো ডেলিভারি একটি নতুন id পায়, সাথে redelivery_of (যে ডেলিভারি আবার পাঠানো হচ্ছে তার আইডি) আর delivery_root (এই চেইনের প্রথম ডেলিভারির আইডি) ফিল্ড।
সিগনেচার যাচাই করুন
প্রতিটি ওয়েবহুকের নিজস্ব সাইনিং সিক্রেট আছে (৩২টি hex অক্ষর)। আপনি এটি ঠিক একবারই দেখেন: ওয়েবহুক তৈরির শেষ ধাপে আর “সিক্রেট ↺”-এর ঠিক পরে। সাথে সাথে এটি আপনার সার্ভারে কপি করুন – LinkHarbor পরে আর এটি দেখায় না। LinkHarbor এটি দিয়ে সিগনেচার এভাবে হিসাব করে:
- বার্তা তৈরি করুন: টাইমস্ট্যাম্প, ডট, ডেলিভারি আইডি, ডট, কাঁচা বডি – অর্থাৎ timestamp.delivery_id.body
- সাইনিং সিক্রেটকে কী হিসেবে নিয়ে এই বার্তার ওপর HMAC-SHA256 হিসাব করুন
- ফলাফলটি sha256= প্রিফিক্সসহ hex স্ট্রিং হিসেবে পাঠান
আপনার সার্ভারের উচিত কনস্ট্যান্ট-টাইম তুলনা দিয়ে সিগনেচার যাচাই করা, ৩০০ সেকেন্ডের বেশি পুরোনো টাইমস্ট্যাম্পের ডেলিভারি প্রত্যাখ্যান করা এবং পুনরাবৃত্তি চিনতে ডেলিভারি আইডিগুলো অন্তত ততক্ষণ সংরক্ষণ করা। গুরুত্বপূর্ণ: সাইন করা হয় কাঁচা বডি, ঠিক যেভাবে তা পৌঁছায় – আপনার নতুন করে এনকোড করা JSON নয়।
import crypto from 'node:crypto';
import express from 'express';
const app = express();
const SECRET = process.env.LH_WEBHOOK_SECRET;
const seen = new Set(); // প্রোডাকশনে: মেয়াদসহ একটি ডেটাবেস বা Redis
app.post('/webhooks/linkharbor', express.raw({ type: 'application/json' }), (req, res) => {
const ts = req.get('X-LinkHarbor-Timestamp') || '';
const id = req.get('X-LinkHarbor-Delivery-Id') || '';
const sig = req.get('X-LinkHarbor-Signature') || '';
if (!/^\d+$/.test(ts) || Math.abs(Date.now() / 1000 - Number(ts)) > 300) {
return res.status(400).send('timestamp');
}
const expected = 'sha256=' + crypto
.createHmac('sha256', SECRET)
.update(ts + '.' + id + '.')
.update(req.body) // Buffer হিসেবে কাঁচা বডি
.digest('hex');
const a = Buffer.from(expected);
const b = Buffer.from(sig);
if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
return res.status(401).send('signature');
}
const event = JSON.parse(req.body.toString('utf8'));
const key = event.delivery_root || event.id; // একই চেইনের পুনরায় পাঠানো ডেলিভারি চিনুন
if (!seen.has(key)) {
seen.add(key);
// এখানে প্রসেস করুন, ভালো হয় একটি কিউতে অ্যাসিঙ্ক্রোনাসভাবে
}
res.sendStatus(200);
});
app.listen(3000); <?php
$secret = getenv('LH_WEBHOOK_SECRET');
$body = file_get_contents('php://input');
$ts = $_SERVER['HTTP_X_LINKHARBOR_TIMESTAMP'] ?? '';
$id = $_SERVER['HTTP_X_LINKHARBOR_DELIVERY_ID'] ?? '';
$sig = $_SERVER['HTTP_X_LINKHARBOR_SIGNATURE'] ?? '';
if (!ctype_digit($ts) || abs(time() - (int)$ts) > 300) {
http_response_code(400);
exit('timestamp');
}
$expected = 'sha256=' . hash_hmac('sha256', $ts . '.' . $id . '.' . $body, $secret);
if (!hash_equals($expected, $sig)) {
http_response_code(401);
exit('signature');
}
$event = json_decode($body, true);
// $event['delivery_root'] ?? $event['id'] দিয়ে ডুপ্লিকেট ডেলিভারি চিনুন,
// তারপর প্রসেস করুন।
http_response_code(200); curl দিয়ে আপনার এন্ডপয়েন্ট টেস্ট করুন
এই স্ক্রিপ্টটি আপনার নিজের সার্ভারে সঠিকভাবে সাইন করা একটি টেস্ট ডেলিভারি পাঠায় – LinkHarbor-এ ওয়েবহুক তৈরির আগে কাজে লাগে:
SECRET="your-signing-secret"
URL="https://example.com/webhooks/linkharbor"
TS=$(date +%s)
ID=$(uuidgen | tr 'A-Z' 'a-z')
BODY='{"id":"'"$ID"'","event":"webhook.test","created_at":"2026-11-01T09:30:12+00:00","data":{"message":"এটি এই ওয়েবহুকের জন্য একটি টেস্ট ইভেন্ট।"}}'
SIG="sha256=$(printf '%s' "$TS.$ID.$BODY" | openssl dgst -sha256 -hmac "$SECRET" -hex | sed 's/^.* //')"
curl -X POST "$URL" \
-H "Content-Type: application/json" \
-H "X-LinkHarbor-Event: webhook.test" \
-H "X-LinkHarbor-Delivery-Id: $ID" \
-H "X-LinkHarbor-Timestamp: $TS" \
-H "X-LinkHarbor-Signature: $SIG" \
-H "X-LinkHarbor-Signature-Version: v1" \
-d "$BODY" রেসপন্স, টাইমআউট আর পুনরায় পাঠানো
- 2xx স্ট্যাটাসের যেকোনো রেসপন্স সফল হিসেবে গণ্য হয়; রিডাইরেক্ট (3xx) অনুসরণ করা হয় না
- আপনার সার্ভার উত্তর দেওয়ার জন্য ১০ সেকেন্ড পায়, আর সংযোগ স্থাপনের জন্য সর্বোচ্চ ৫ সেকেন্ড
- একটি ইভেন্টের সব ওয়েবহুক মিলিয়ে মোট ২৫ সেকেন্ড পায়; ততক্ষণে যাদের পালা আসেনি সেগুলো ব্যর্থ হিসেবে চিহ্নিত হয় এবং আবার পাঠানো যায়
- LinkHarbor ব্যর্থ ডেলিভারি স্বয়ংক্রিয়ভাবে আবার চেষ্টা করে না
- ব্যর্থ ডেলিভারি আপনি হাতে আবার পাঠাতে পারেন, কিন্তু যেটি পরে সফল হয়েছে সেটি নয়। পুনরায় পাঠানো ডেলিভারির নতুন id আর নতুন created_at থাকে
- প্রতি ইভেন্টে প্রথম ডেলিভারিসহ সর্বোচ্চ ৩টি চেষ্টা অনুমোদিত; এরপর এটি “ডেড লেটার”-এ চলে যায় এবং আর পাঠানো যায় না
ড্যাশবোর্ডে ডেলিভারি
“ডেলিভারি” একটি ওয়েবহুকের লগ খোলে। এতে তিনটি ট্যাব আছে:
- “সব ডেলিভারি”
- সব ডেলিভারি, ইভেন্ট, স্ট্যাটাস (“সফল (2xx)”, “ক্লায়েন্ট ত্রুটি (4xx)”, “সার্ভার ত্রুটি (5xx)”, “ব্যর্থ”) আর “সীমা”-এর ফিল্টারসহ। “↺ আবার চেষ্টা” একটি ব্যর্থ ডেলিভারি আবার পাঠায়, যতক্ষণ পরে কোনো সফল ডেলিভারি না থাকে। কোনো সারিতে ক্লিক করলে রিকোয়েস্ট, রেসপন্স, বডি আর কাঁচা JSON দেখা যায়।
- “রিপ্লে”
- পুনরায় পাঠানোর চেইন, “পুনরুদ্ধার হয়েছে” বা “এখনো ব্যর্থ হচ্ছে” ফলাফল আর চেষ্টার সংখ্যাসহ।
- “ডেড লেটার”
- যেসব ডেলিভারিতে অনুমোদিত প্রতিটি চেষ্টা ব্যর্থ হয়েছে – প্রথম ডেলিভারি আর পুনরায় পাঠানোগুলো মিলিয়ে। ট্যাবটি শুধু দেখার জন্য: এগুলো আর আবার পাঠানো যায় না। আপনার এন্ডপয়েন্ট যাচাই করুন; এরপর নতুন ইভেন্ট আগের মতোই পৌঁছায়। ডেটা দরকার হলে API দিয়ে নিয়ে আসুন।
পুনরায় পাঠানো না গেলে ড্যাশবোর্ড কারণ জানায়:
- “আবার পাঠানো হয়নি: এই ইভেন্টটি ইতিমধ্যে … বার ব্যর্থ হয়েছে, আর চেষ্টা করা সম্ভব নয়। এটি ‘ডেড লেটার’-এ পাবেন।”
- ৩টি চেষ্টাই শেষ হয়ে গেছে।
- “আবার পাঠানো হয়নি: এই ইভেন্টটি ইতিমধ্যে সফলভাবে পৌঁছে গেছে।”
- একই চেইনের পরের একটি ডেলিভারি আগেই সফল হয়েছে।
ড্যাশবোর্ডে যাচাইকরণ
“যাচাইকরণ”-এর অধীনে দুটি সহায়ক টুল পাবেন:
- “যাচাইকরণ কিট”
- “কিট লোড করুন” অ্যালগরিদম, হেডারের নাম, সাইন করা বার্তার ফরম্যাট আর ৩০০ সেকেন্ডের প্রস্তাবিত সহনসীমা দেখায়। সিক্রেট নিজে এতে থাকে না।
- “সিগনেচার যাচাই করুন”
- আপনার পাওয়া একটি ডেলিভারির ডেলিভারি আইডি, টাইমস্ট্যাম্প, সিগনেচার আর কাঁচা রিকোয়েস্ট বডি দিন। LinkHarbor তখন জানায় “সিগনেচার সঠিক” বা “সিগনেচার সঠিক নয়”। টাইমস্ট্যাম্প আর সিগনেচার কপি করুন X-LinkHarbor-Timestamp আর X-LinkHarbor-Signature হেডার থেকে। যাচাই শুধু গত ৫ মিনিটের ডেলিভারির জন্য কাজ করে; পুরোনোগুলোর ক্ষেত্রে সিগনেচার সঠিক হলেও এটি “সিগনেচার সঠিক নয়” জানায়।
সিক্রেট রোটেট, নিষ্ক্রিয় ও মোছা
- “সিক্রেট ↺” একটি নতুন সাইনিং সিক্রেট তৈরি করে একবার দেখায়; পুরোনোটি সাথে সাথে কাজ করা বন্ধ করে, আর আপনার সার্ভারকে নতুনটি ব্যবহার করতে হবে
- ডেলিভারি থামাতে “সম্পাদনা করুন”-এ স্ট্যাটাস “নিষ্ক্রিয়” করুন
- ডাস্টবিন আইকন ওয়েবহুকটি মুছে দেয়; বার্তাটি বন্ধ না করা পর্যন্ত “আনডু” দিয়ে তা ফেরাতে পারেন
ছোট প্ল্যানে গেলে নতুন সীমার ওপরের ওয়েবহুকগুলো নিষ্ক্রিয় হয়, আর Creator Free-তে সবগুলো। এগুলো রেখে দেওয়া হয়; আপগ্রেডের পর LinkHarbor নতুন প্ল্যানের সীমা পর্যন্ত নিষ্ক্রিয় ওয়েবহুকগুলো স্বয়ংক্রিয়ভাবে আবার চালু করে – যেগুলো আপনি নিজে নিষ্ক্রিয় করেছিলেন সেগুলোও।
এগুলোও কাজে আসতে পারে
কিছু খুঁজে পাননি?
আপনার কী দরকার তা আমাদের জানান, আমাদের সাপোর্ট টিম ব্যক্তিগতভাবে আপনাকে সাহায্য করবে।