گفت‌وگوی پیام‌رسان را کنار پرونده مشتری نگه دارید

وقتی مشتری در ایتا، بله، روبیکا، سروش‌پلاس یا تلگرام پیام می‌دهد، تیم فروش و پشتیبانی نباید بین چند پنل پراکنده جابه‌جا شود تا بفهمد با چه کسی صحبت می‌کند و کی آخرین بار پاسخ داده است. یونیوم هر پیام ورودی را به وب‌هوک CRM می‌رساند، پاسخ اپراتور را با یک کلید API محدود و حساب مشخص ارسال می‌کند، و هر ارسال را به رکورد مشتری لاگ می‌زند؛ همه از همان قالب آشنای Telegram Bot API و یک base_url.

۳ سطح تطبیق مخاطب ۱ وب‌هوک مشترک scope برای هر اپراتور idempotent لاگ گفت‌وگو
تطبیق مخاطبشماره، شناسه پیام‌رسان یا شناسه داخلی به رکورد CRM
صف ورودیوب‌هوک، سپردن به مسئول و سابقه گفت‌وگو
پاسخ از CRMارسال با کلید محدود و لاگ قابل پیگیری

مشکل، خودِ ارسال پیام نیست؛ از دست رفتن زمینه است

بیشتر تیم‌های فروش و پشتیبانی ایرانی پیام‌رسان‌ها را دستی جواب می‌دهند، یا یک پنل اس‌ام‌اس کنار یک کاره واتساپ و یک ربات تلگرام نگه می‌دارند. نتیجه‌اش همیشه یک شکل است: متوجه نمی‌شوند «این مخاطبِ ایتا، همان کاربری است که هفته پیش در بله خرید کرد»، نمی‌دانند کدام اپراتور پاسخ داده، و هیچ مسیر حسابرسی از «چه پیامی، از طرف کی، در چه زمانی» در کنار رکورد مشتری نمی‌ماند. وقتی اپراتور تغییر می‌کند یا مشتری در پیام‌رسان دیگری برمی‌گردد، زمینه گم می‌شود. یونیوم لایه انتقال پیام را یکسان می‌کند تا CRM روی مسئله واقعی تمرکز کند: مالکیت داده مشتری.

  • شناسه پیام‌رسان (chat_id) را به یک رکورد یکتای CRM نگاشت کنید، نه به یک کانال جدا.
  • پاسخ هر اپراتور را با یک کلید API با scope محدود و credential_id مشخص ارسال کنید.
  • برای پیام ورودی تکراری یا وب‌هوکی که دوباره می‌رسد، ثبت سابقه را idempotent طراحی کنید.
  • مالکیت رضایت و لغو دریافت را در CRM نگه دارید، نه در لایه پیام‌رسان.

از پیام ورودی تا پاسخ ثبت‌شده در پرونده

یک مسیر مینی‌مال و قابل اتکا. هدف این است که وب‌هوک را سریع تأیید کنید و کار سنگین (تطبیق، ذخیره، ارسال) را در صف داخلی خودتان انجام دهید، نه در بدنه‌ی هندلر وب‌هوک.

دریافت و تأیید سریع وب‌هوک

یونیوم پیام ورودی از ایتا، بله یا تلگرام را به POST وب‌هوک شما می‌زند. در کمتر از ۲ ثانیه با HTTP 200 تأیید کنید، پیام را در صف داخلی بیندازید و بلافاصله هندلر را رها کنید. اگر دیر تأیید کنید، یونیوم طبق سیاست retry دوباره می‌فرستد و خطر پاسخ دوگانه بالا می‌رود.

تطبیق مخاطب و تعیین مالک

در صف، chat_id و platform_id را به رکورد CRM نگاشت کنید (با شماره تلفن، نام کاربری یا شناسه داخلی). سپس مالک فعلی مکالمه را پیدا کنید؛ همین که «مسئول فروش» یا «پشتیبانی» روی پرونده مشخص است، ارجاع روشن می‌ماند.

پاسخ از داخل CRM

اپراتور در همان صفحه پرونده پاسخ را می‌نویسد. CRM با کلید API محدود خود و به ازای credential_id درست، یک sendMessage به همان base_url یونیوم می‌زند. یونیوم ارسال را به پیام‌رسان مقصد می‌سپارد و message_id و نتیجه را برمی‌گرداند.

ثبت سابقه و خطا

پیام ورودی، پاسخ ارسالی، message_id، اپراتور و نتیجه ارسال را به رکورد مشتری لاگ کنید. این تاریخچه همان مسیر حسابرسی است که هنگام اختلاف یا تحویل به اپراتور بعدی نیاز می‌شوید.

نکته: اگر وب‌هوک CRM کند باشد (مثلاً پایگاه‌داده قفل کرده)، یونیوم طبق سیاست retry دوباره می‌فرستد. یک صف داخلی با dedup روی update_id این خطر را کنترل می‌کند؛ بدون صف، کاربر ممکن است یک پاسخ را دو بار ببیند.

شش قطعه‌ای که یک ادغام CRMِ قابل اتکا می‌سازند

هیچ‌کدام از این‌ها ویژگی تبلیغاتی نیستند؛ هر کدام یک تصمیم طراحی مشخص هستند که بدونش ادغام CRM در حجم بالا می‌شکند.

تطبیق مخاطب سه‌سطحی

شماره تلفن، شناسه پیام‌رسان (chat_id) و شناسه داخلی CRM را به یک رکورد مشتری یکتا نگاشت کنید. یک مشتری که در ایتا و بله دو حساب دارد، نباید دو پرونده جدا بگیرد.

کلید API با scope

برای هر تیم یا اپراتور یک کلید با scope و credential_id محدود بسازید. فروش فقط از حساب فروش، پشتیبانی فقط از حساب پشتیبانی؛ لاگ ارسال نشان می‌دهد کلیدِ کی پیام را فرستاده.

لاگ idempotent

ثبت سابقه را روی کلید یکتای پیام (مثلاً update_id برای ورودی و request_id برای ارسال) طراحی کنید تا وب‌هوک تکراری یا retry، پاسخ تکراری نسازد. این بزرگ‌ترین منبع «پاسخ دوگانه به مشتری» است.

مالکیت رضایت در CRM

وضعیت «آیا این مشتری می‌خواهد پیام بگیرد؟» باید در CRM بماند، نه در یونیوم. قبل از هر ارسال، CRM تصمیم می‌گیرد؛ یونیوم فقط لایه انتقال است و قواعد هر پلتفرم همچنان پابرجاست.

ارجاع روشن بین اپراتورها

وقتی فروش به پشتیبانی تحویل می‌دهد، مالک مکالمه در CRM عوض می‌شود و کلید بعدی از همان scope جدید استفاده می‌کند. این یعنی هیچ اپراتوری نمی‌تواند از حساب نامعتبر پیام بفرستد.

فشار پشتیبانی به عقب‌نشینی

اگر CRM کُند شد یا صف پر شد، به جای بمباران یونیوم با درخواست، نرخ ارسال را در سمت خود کم کنید. یونیوم کلاینت‌ها و وب‌هوک‌ها را با timeout و rate-limit نگه می‌دارد؛ فراتر از این محدودیت‌ها 429 می‌گیرید.

چه چیزی این ادغام را می‌شکند

این فهرست از خطاهای واقعی که در لاگ‌های message_logs دیده‌ایم برداشته شده؛ جدی بگیرید.

هندل وب‌هوک در بدنه‌ی endpoint

اگر تطبیق مخاطب و ذخیره در دیتابیس را داخل همان هندلر وب‌هوک انجام دهید، یک کندی پایگاه‌داده کافی است تا تأیید 200 دیر برسد، یونیوم retry کند و مشتری دو بار پاسخ ببیند. کار سنگین را به صف بفرستید، endpoint فقط تأیید کند.

نداشتن dedup روی update_id

بدون یک کلید یکتا روی پیام ورودی، هر retry یونیوم به چشم یک مکالمه جدید دیده می‌شود. نتیجه: پاسخ‌های تکراری، پرونده‌های کپی و اپراتور گیج. راه‌حل: ستون یکتا روی (platform_id, update_id).

یک کلید API برای کل تیم

کلید مشترک یعنی نمی‌توانید در لاگ ببینید چه کسی پیام را فرستاده، و نمی‌توانید دسترسی یک اپراتور اخراجی را قطع کنید. به ازای هر نقش یک کلید با scope و credential_id جدا بسازید.

تکیه بر نام کاربری به جای chat_id

@username در تلگرام یا بله قابل تغییر است و در ایتا/روبیکا اصلاً معنای یکسانی ندارد. کلید اصلی تطبیق را chat_id عددی قرار دهید و نام کاربری را فقط فیلد نمایشی نگه دارید.

فرض بر اینکه همه پیام‌رسان‌ها یکسان‌اند

API واحد به معنی برابری همه قابلیت‌ها نیست. ویس فقط در برخی پلتفرم‌ها، دکمه شیشه‌ای (inline keyboard) فقط در تلگرام و بله، و وضعیت آنلاین فقط در ایتا و بله معنی دارد. قبل از ساخت، ماتریس پایین صفحه را ببینید.

نادیده گرفتن قواعد هر پلتفرم

ارسال انبوه به یک حساب کاربری خارج از قواعد پلتفرم، ریسک مسدود شدن حساب (INVALID_AUTH یا قطع سشن) را بالا می‌برد. مالکیت حساب‌ها و حجم ارسال را واقعی نگه دارید.

کدام پیام‌رسان برای CRM شما می‌رسد

انتخاب به رفتار مشتری شما بستگی دارد، نه به محبوبیت پلتفرم. معمولاً راهکار درست، چندپیام‌رسانی است: یک کانال برای تراکنشی و یکی برای گفت‌وگوی انسانی.

بله برای CRM تراکنشی و خدماتی جذاب است چون هم API رسمی (بازو) دارد و هم خدمات دولتی/بانکی در کنارش می‌چیند؛ ایتا و سروش‌پلاس برای کانال‌ها و دسترسی بدون فیلتر به مخاطب عمومی قوی‌اند؛ تلگرام وقتی مخاطب آنجاست و تیم با ربات رسمی کار می‌کند، هنوز مرجع API است؛ روبیکا برای دسترسی به بیشترین کاربر فعال روزانه میان پیام‌رسان‌های ایرانی مناسب است. ترکیب رایج: بله + تلگرام برای فروش، ایتا + سروش‌پلاس برای اطلاع‌رسانی و دسترسی گسترده.

هر قابلیت، روی کدام پلتفرم

این ماتریس صادقانه نشان می‌دهد چه چیزی پشتیبانی می‌شود و چه محدودیت‌هایی دارد. ستون «یادداشت» را جدی بگیرید؛ همین محدودیت‌ها هستند که معماری تطبیق مخاطب را شکل می‌دهند.

ارسال و دریافت متن

بله، ایتا، سروش‌پلاس، روبیکا، تلگرام — همه پشتیبانی می‌شوند. پایه‌ی هر CRM است. محدودیت طول متن تابع پلتفرم است؛ متن طولانی را خرد یا به مدیا تبدیل کنید.

ویس و فایل صوتی

عمدتاً بله و ایتا، و تلگرام. اگر جریان فروش شما روی ویس است، ابتدا پلتفرم مقصد را در playground تست کنید؛ قالب فایل و مدت محدودیت ایجاد می‌کند.

دکمه شیشه‌ای (inline keyboard)

تلگرام و بله. برای منوی انتخاب مرحله در CRM (مثلاً «پاسخ به سفارش» / «ارجاع به پشتیبانی») کاربردی است، اما روی همه پلتفرم‌ها در دسترس نیست؛ همیشه مسیر متنی پشتیبان نگه دارید.

وضعیت آنلاین / فعالیت

فقط برخی پلتفرم‌ها (عمدتاً ایتا و بله). به «دیده شدن پیام» تکیه نکنید؛ برای تصمیم «آیا الان پاسخ بدهم؟» از مدت زمان از آخرین پیام ورودی استفاده کنید، نه از وضعیت آنلاین.

نام کاربری ثابت (@username)

تلگرام و بله؛ در ایتا/روبیکا/سروش‌پلاس معنای یکسانی ندارد. کلید تطبیق را chat_id بگذارید، @username را فقط برای نمایش نگه دارید.

وب‌هوک ورودی

همه پلتفرم‌ها از طریق یونیوم یک وب‌هوک واحد با قالب آشنا می‌فرستند. این یعنی CRM شما یک endpoint می‌نویسد، نه پنج تا؛ تفاوت‌ها در صف داخلی مدیریت می‌شوند.

API واحد به معنی برابری همه قابلیت‌ها نیست. تفاوت قابلیت پلتفرم‌ها در صفحات ارائه‌دهنده شفاف باقی می‌ماند؛ قبل از مهاجرت کامل، جریان خود را در playground آزمایش کنید.

چک‌لیست راه‌اندازی CRM

این ترتیب پیشنهادی است که جلوی رایج‌ترین خطاهای ادغام را می‌گیرد. از یک پیام‌رسان و یک جریان ساده شروع کنید، بعد گسترش دهید.

  • یک credential_id واحد (مثلاً بله) را به کلید با scope محدود وصل کنید و اولین sendMessage را در playground بزنید.
  • وب‌هوک را با HTTPS راه بیندازید، در داشبورد ثبت کنید، و یک پیام آزمایشی به حساب کاربری خود بفرستید تا رسیدنش را ببینید.
  • جدول تطبیق (chat_id + platform_id → crm_contact_id) را با ستون یکتا بسازید.
  • صف داخلی با dedup روی update_id پیاده کنید و هندلر وب‌هوک را فقط به تأیید 200 محدود کنید.
  • برای هر نقش (فروش، پشتیبانی) کلید جدا با scope و credential_id بسازید؛ لاگ را به اپراتور وصل کنید.
  • پیش از هر ارسال، گزینه رضایت/لغو را از CRM بخوانید؛ ارسال بدون رضایت را مسدود کنید.
  • مانیتورینگ روی 429، INVALID_AUTH و transport failed راه بیندازید؛ این‌ها نشانه‌های زودهنگام مشکل سشن یا حجم‌اند.

ابزارهایی که با CRM شما هماهنگ می‌شوند

یونیوم فقط ارسال پیام نیست؛ به‌هوک ورودی‌اش می‌تواند مستقیم به ابزارهای مشتری محور شما وصل شود. الگوی مشترک: پیام می‌آید، رکورد ساخته می‌شود، پاسخ از همان ابزار برمی‌گردد.

Chatwoot

به‌هوک یونیوم یک گفتگوی جدید در Chatwoot می‌سازد؛ اپراتور از inbox پاسخ می‌دهد و Chatwoot با API خودش همان پیام را برمی‌گرداند.

Zendesk

پیام ورودی با موضوع شماره تلفن کاربر به تیکت تبدیل می‌شود؛ پاسخ تیکت از طریق API Zendesk روی همان کانال ارسال می‌شود.

HubSpot CRM

از شناسه پیام‌رسان (chat_id) برای تطبیق یا ساخت مخاطب HubSpot استفاده کنید؛ همه فعالیت‌ها کنار پرونده مشتری لاگ می‌شوند.

Google Sheets

بدون بک‌اند: پیام جدید یک ردیف در شیت می‌سازد و پاسخ اپراتور از یک ستون PENDING به‌صورت متنی ارسال می‌شود.

برای اتصال به هر CRM، به‌هوک را با HTTPS ثبت کنید و همان یک endpoint را در سمت CRM وصل کنید؛ نه پنج endpoint جدا برای هر پیام‌رسان.

اول یک مسیر پیام را به CRM وصل کنید

یک حساب آزمایشی، یک کلید با scope، و یک وب‌هوک. دریافت پیام، تطبیق مخاطب و پاسخ از CRM را با ۱۰۰۰ پیام رایگان پلن رایگان بسنجید؛ حجم و پیام‌رسان‌های بیشتر را بعد اضافه کنید.

باز کردن playground