পাবলিক API এবং ওয়েবহুক
REST API আপনার CRM, সাইটের ব্যাকএন্ড বা নিজের বটকে cenaly.com-এর লিড ও ডায়ালগ নিয়ে ঠিক প্যানেলের মতো কাজ করার সুযোগ দেয়: কার্ড পড়া, প্রপার্টি বদলানো, ইভেন্ট পাঠানো, ডায়ালগে উত্তর দেওয়া। ওয়েবহুক উল্টোটা করে — নতুন লিড, ইভেন্ট ও মেসেজ সম্পর্কে নিজেই আপনার সার্ভারকে জানায়।
চালু করতে যা দরকার#
| কী | কোথায় |
|---|---|
| রোল | অ্যাকাউন্টের মালিক — কী তাঁর নামে কাজ করে; কর্মীরা কী দেখতে পান না |
| বিভাগ | চালু করা চ্যাট (লিড ও ডায়ালগ এখানেই থাকে) |
| কী | ইন্টিগ্রেশন → API এবং ওয়েবহুক → কী → কী তৈরি করুন |
| API-এর ঠিকানা | https://api.cenaly.com/public-api/v1 |
| মেথডের রেফারেন্স | api.cenaly.com/public-api/v1/docs |
| OpenAPI 3.1 | api.cenaly.com/public-api/v1/openapi.json |
ধাপ ১. কী ও অধিকার#
- ইন্টিগ্রেশন খুলুন এবং পেজের হেডারে API এবং ওয়েবহুক চাপুন।
- কী ট্যাবে কী তৈরি করুন চাপুন, একটি নাম লিখুন (“CRM”, “সাইটের ব্যাকএন্ড”, “Telegram-বট”)।
- অধিকারের একটি সেট বেছে নিন বা এক এক করে টিক দিন, একাধিক শাখা থাকলে — কোন কোন শাখায় কী-এর অনুমতি থাকবে, এবং মেয়াদ।
- সিক্রেট
cnk_…কপি করুন। এটি একবারই দেখানো হয়: আমাদের কাছে শুধু এর ফিঙ্গারপ্রিন্ট (SHA-256) সংরক্ষিত থাকে।
| অধিকার | কী দেয় |
|---|---|
contacts:read |
লিডের তালিকা, সার্চ ও কার্ড, প্রপার্টি |
contacts:write |
প্রপার্টি ও ট্যাগ বদলানো, মার্জ করা, সাবজেক্টের অনুরোধে মুছে ফেলা |
events:read |
লিডের ইভেন্ট ফিড |
events:write |
ইভেন্ট পাঠানো (ক্রয়, রেজিস্ট্রেশন, যেকোনো নিজের) |
conversations:read |
ডায়ালগ ও মেসেজ |
conversations:write |
অপারেটরের উত্তর, নোট, স্ট্যাটাস, দায়িত্বপ্রাপ্ত, লেবেল |
messages:send |
লিডের সর্বশেষ ডায়ালগে মেসেজ |
segments:read |
সংরক্ষিত সেগমেন্ট ও তাদের সদস্য |
সেট: CRM / ব্যাকএন্ড (লিড, প্রপার্টি, ইভেন্ট, ডায়ালগ ও সেগমেন্ট পড়া), নিজের বট (লিড পড়ে, ডায়ালগে উত্তর দেয়, লিডকে লেখে), শুধু পড়া, সব।
- অধিকার কী-এর অধিকার ও শাখা সঙ্গে সঙ্গে বদলায় — ইন্টিগ্রেশন কাজ করতে থাকে।
- পুনরায় ইস্যু করুন নতুন সিক্রেট দেয়; পুরোনোটি সঙ্গে সঙ্গে কাজ করা বন্ধ করে, অধিকার ও জার্নাল থেকে যায়।
- প্রত্যাহার করুন — সঙ্গে সঙ্গে এবং চিরতরে, পরের রিকোয়েস্ট
401পাবে।
কী পাঠানো হয় Authorization: Bearer cnk_… হেডারে (বা X-Api-Key: cnk_…)। এটি শুধু সার্ভারে রাখুন — ব্রাউজারে বা মোবাইল অ্যাপে নয়।
ধাপ ২. প্রথম রিকোয়েস্ট#
KEY=cnk_ваш_ключ
API=https://api.cenaly.com/public-api/v1
# কী কী করতে পারে: অধিকার, শাখা, লিমিট
curl -H "Authorization: Bearer $KEY" "$API/me"
# লিড, নতুনগুলো উপরে (পেজে ২০টি)
curl -H "Authorization: Bearer $KEY" "$API/contacts?limit=20"
# নাম, ইমেইল বা ফোন দিয়ে সার্চ
curl -H "Authorization: Bearer $KEY" "$API/contacts?q=anna"
উত্তর সবসময় একটি খাম:
{
"meta": { "status": 200, "requestId": "…", "nextCursor": "WyIyMDI2LTEwLTA0…" },
"data": { "total": 128, "contacts": [ { "id": "…", "status": "lead", "name": "Анна", "updatedAt": "2026-10-04T09:12:00Z" } ] }
}
পরের পেজ — একই রিকোয়েস্ট cursor=<meta.nextCursor> দিয়ে; nextCursor না থাকলে আর পেজ নেই। ত্রুটি — {"meta": {...}, "error": {"code": "…"}}।
শাখা। কী-এর অধিকার একটিমাত্র শাখায় থাকলে তা উল্লেখ করার দরকার নেই। একাধিক হলে location=<শাখার id> যোগ করুন (তালিকা — GET /v1/locations), নাহলে উত্তর 400 location_required।
আপনার user_id দিয়ে প্রপার্টি ও ইভেন্ট। আমাদের লিড id রাখা বাধ্যতামূলক নয়: ?by=user_id যোগ করুন, আর ঠিকানা হয়ে যাবে আপনার ইউজার আইডেন্টিফায়ার। এই user_id-এর লিড এখনো না থাকলে — আমরা সেটি তৈরি করব।
# প্রপার্টি: অপারেশন update_or_create, set_once, add, delete, append, union, exclude
curl -X POST -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"ops":[{"op":"update_or_create","key":"$email","value":"anna@example.com"},
{"op":"add","key":"orders","value":1},
{"op":"union","key":"interests","value":"yoga"}]}' \
"$API/contacts/u-1001/props?by=user_id"
# ইভেন্ট ব্যাচে (১০০ পর্যন্ত), একই id দিয়ে পুনরাবৃত্তি একবারই গোনা হয়
curl -X POST -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"events":[{"id":"ord-5531","userId":"u-1001","name":"order_paid","props":{"sum":45,"currency":"GEL"}}]}' \
"$API/events"
# ডায়ালগে উত্তর ও স্ট্যাটাস পরিবর্তন
curl -X POST -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"text":"Здравствуйте! Заказ передан курьеру."}' "$API/conversations/<id>/reply"
curl -X POST -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"status":"resolved"}' "$API/conversations/<id>/status"
রেকর্ডিং প্যানেলের সম্পাদনার মতো একই কিউ দিয়ে যায়: পরিবর্তন কয়েক সেকেন্ডে প্রয়োগ হয়, আর user_id দিয়ে লেখার উত্তরে আসে 202 সঙ্গে pending। লিডের কার্ডে সম্পাদনার লেখক দেখা যায় “API: <কী-এর নাম>” হিসেবে।
মেথড#
| মেথড | কী করে | অনুমতি |
|---|---|---|
GET /v1/me, GET /v1/locations |
কী, অনুমতি, শাখা | — |
GET /v1/contacts |
লিড: status (anon, lead, user), q, limit, cursor |
contacts:read |
GET /v1/contacts/{id} |
কার্ড: বৈশিষ্ট্য, ট্যাগ, ইভেন্টের সারসংক্ষেপ | contacts:read |
POST /v1/contacts/{id}/props |
অপারেশন দিয়ে বৈশিষ্ট্য (সর্বোচ্চ 250) বা {"props":{…}} |
contacts:write |
POST / DELETE /v1/contacts/{id}/tags |
লিডের ট্যাগ | contacts:write |
POST /v1/contacts/merge |
দুটি কার্ড একত্র করা: প্রিভিউ, তারপর "apply": true |
contacts:write |
POST /v1/contacts/{id}/erase |
সাবজেক্টের অনুরোধে মুছে ফেলা ("confirm": true) |
contacts:write |
GET /v1/contacts/{id}/events |
লিডের ইভেন্ট ফিড | events:read |
POST /v1/contacts/{id}/events, POST /v1/events |
ইভেন্ট (একবারে সর্বোচ্চ 100) | events:write |
GET /v1/contacts/{id}/conversations |
লিডের কথোপকথন | conversations:read |
POST /v1/contacts/{id}/messages |
লিডের সর্বশেষ কথোপকথনে তাকে লিখুন | messages:send |
GET /v1/conversations, /{id}, /{id}/messages |
কথোপকথন ও বার্তা | conversations:read |
POST /v1/conversations/{id}/reply |
অপারেটরের উত্তর বা নোট ("type": "note") |
conversations:write |
POST /v1/conversations/{id}/status, /assign, /tags |
স্ট্যাটাস, দায়িত্বপ্রাপ্ত, লেবেল | conversations:write |
GET /v1/segments, GET /v1/segments/{id}/contacts |
সেগমেন্ট ও তাদের সদস্য | segments:read |
প্রতিটি মেথডের ফিল্ড, উদাহরণ ও এরর কোড — রেফারেন্সে।
ধাপ 3. ওয়েবহুক#
ওয়েবহুক শাখায় কনফিগার করা হয়: চ্যাট → সেটিংস → ওয়েবহুক — https ঠিকানা, ইভেন্ট ও সিগনেচার সিক্রেট। কথোপকথনের ইভেন্টগুলো (নতুন কথোপকথন, নতুন বার্তা, স্ট্যাটাস, রেটিং, লেবেল) ছাড়াও লিডের ইভেন্ট যোগ হয়েছে:
| ইভেন্ট | কখন আসে |
|---|---|
lead.created |
নতুন লিড এসেছে (চ্যাটে, ফর্মে কন্টাক্ট রেখে যাওয়া হয়েছে বা API দিয়ে তৈরি হয়েছে) |
lead.props_changed |
লিডের বৈশিষ্ট্য বদলেছে — কী-এর তালিকা changedProps-এ |
lead.event_tracked |
লিডের একটি ইভেন্ট ঘটেছে; ডিফল্টভাবে সিস্টেম ইভেন্ট ($…) ছাড়া আপনার সব ইভেন্ট, নামের তালিকা “কোন ইভেন্ট পাঠাবেন” ফিল্ডে দেওয়া হয় |
message.goal_reached |
লিড বার্তার লক্ষ্যে পৌঁছেছে (পপ-আপ, ক্যাম্পেইন) |
{
"event": "lead.event_tracked",
"deliveryId": "WD…",
"at": "2026-10-04T09:12:03Z",
"webhookId": "…",
"locationId": "…",
"contact": { "id": "…", "status": "user", "userId": "u-1001", "props": { "orders": 3 }, "tags": ["vip"] },
"leadEvent": { "name": "order_paid", "at": "2026-10-04T09:12:00Z", "props": { "sum": 45 } }
}
লিডের নাম, ইমেইল ও ফোন বডিতে যাবে শুধু তখনই, যখন ওয়েবহুকে “গেস্টের কন্টাক্ট পাঠান” চেকবক্স চালু থাকে। সিগনেচার যাচাই — ওয়েবহুকের সিক্রেট দিয়ে বডির HMAC-SHA256:
# заголовок X-Meni-Signature: sha256=<hex>
echo -n "$BODY" | openssl dgst -sha256 -hmac "$SECRET"
৫ সেকেন্ডের মধ্যে 2xx উত্তর দিন — নাহলে ডেলিভারি আবার হবে; দীর্ঘ ধারাবাহিক ব্যর্থতার পর ওয়েবহুক বন্ধ হয়ে যায়, আর তা সেটিংসে দেখা যায়। ডুপ্লিকেট deliveryId দিয়ে ছেঁকে নিন।
সীমাবদ্ধতা#
- প্রতি কী-তে মিনিটে 60 রিকোয়েস্ট; তার বেশি হলে —
Retry-Afterহেডারসহ429। বাকি সীমা —X-RateLimit-*-এ। - প্রতি পেজে সর্বোচ্চ 200 রেকর্ড (ডিফল্ট 50), এক ব্যাচে সর্বোচ্চ 100 ইভেন্ট, প্রতি রিকোয়েস্টে বৈশিষ্ট্যের সর্বোচ্চ 250 অপারেশন, একবারে সর্বোচ্চ 30 ট্যাগ।
- প্রতি অ্যাকাউন্টে সর্বোচ্চ 20 সক্রিয় কী।
- কী-এর কল লগ 30 দিন রাখা হয়: সময়, মেথড, পাথ টেমপ্লেট (id ও বডি ছাড়া), রেসপন্স কোড, সময়কাল।
- API দিয়ে পাঠানো ইভেন্ট লিডের কার্ডে যায় (ফিড, সারসংক্ষেপ, সেগমেন্ট), কিন্তু ভিজিট অ্যানালিটিক্সের কাঁচা লগে নয়।
- লিডকে লেখা যায় শুধু বিদ্যমান কথোপকথনে: কথোপকথন না থাকলে — উত্তর
409 no_conversation।
সমস্যা সমাধান#
| উত্তর | কী বোঝায় | কী করবেন |
|---|---|---|
401 api_key_missing / api_key_invalid |
রিকোয়েস্টে কী নেই, বা তা ভুল, প্রত্যাহৃত বা মেয়াদোত্তীর্ণ | হেডার যাচাই করুন; প্রয়োজনে কী নতুন করে ইস্যু করুন |
403 scope_required |
কী-তে প্রয়োজনীয় অনুমতি নেই | কী-এর অনুমতি — অনুমতি যোগ করুন |
400 location_required |
কী-এর অধীনে একাধিক শাখা আছে | location=<id> যোগ করুন |
404 location_not_found |
কী-এর শাখাগুলোর মধ্যে এই শাখা নেই | GET /v1/locations-এর সঙ্গে মিলিয়ে দেখুন |
404 not_found |
লিড বা কথোপকথন নেই | নিজের id-এর জন্য ?by=user_id ব্যবহার করুন |
429 rate_limited |
মিনিটে 60 রিকোয়েস্টের বেশি | Retry-After সেকেন্ড অপেক্ষা করুন, ইভেন্ট ব্যাচে পাঠান |
502 upstream_error |
সাময়িক ত্রুটি | কিছু পরে রিকোয়েস্ট আবার করুন |
প্রতিটি রিকোয়েস্ট কল লগ ট্যাবে দেখা যায় — রেসপন্স কোড ও কী-এর নামসহ।
সাধারণ প্রশ্ন#
ব্রাউজার থেকে API কল করা যায় কি? না: কী শাখার সব লিডে অ্যাক্সেস দেয়। নিজের সার্ভার থেকে API কল করুন।
লিডের id থেকে user_id কীভাবে আলাদা? লিডের id — কার্ডের আমাদের আইডেন্টিফায়ার। user_id — আপনার ব্যবহারকারীর আইডেন্টিফায়ার (CRM-এ নম্বর, সাইটে অ্যাকাউন্টের id); ?by=user_id দিয়ে কার্ডকে এটি দিয়ে সম্বোধন করা যায়।
একই ইভেন্ট আবার পাঠালে কী হবে? একই id-এর ইভেন্ট একবারই গোনা হয় — নেটওয়ার্ক ত্রুটিতে নিশ্চিন্তে রিকোয়েস্ট আবার পাঠাতে পারেন।
প্রতিটি শাখার জন্য আলাদা কী দরকার? না: একটি কী একাধিক শাখার সঙ্গে কাজ করতে পারে, শাখা location প্যারামিটার দিয়ে বেছে নেওয়া হয়।
সম্পর্কিত বিভাগ#
- গেস্টদের সঙ্গে চ্যাট — কথোপকথন, লিড ও ওয়েবহুক সেটিংস
- অনুরোধ — একক ইনবক্স
- নিজের PBX-এর API ও MCP — আলাদা টেলিফোনি API
- ইন্টিগ্রেশন