توسعه‌دهندگان

Webhooks

رویدادهای شاهو رو در لحظه به سیستم خودت دریافت کن — با احراز هویت HMAC و تلاش مجدد خودکار.

۱۰ دقیقه مطالعه آخرین به‌روزرسانی: ۱۴۰۵/۰۷
Webhook چیست؟ به‌جای اینکه مدام از شاهو بپرسی «پیام جدیدی هست؟»، شاهو خودش به محض وقوع رویداد، به سیستم تو خبر می‌ده.

راه‌اندازی Webhook

  1. در پنل، برو به تنظیمات ← اتصال‌ها
  2. روی افزودن Webhook کلیک کن
  3. آدرس URL خودت رو وارد کن (مثلاً https://example.com/webhook)
  4. رویدادهایی که می‌خوای دریافت کنی رو انتخاب کن
  5. یک Secret Key بساز یا خودت وارد کن
  6. ذخیره کن
مهم: آدرس Webhook باید HTTPS باشه. به‌درخواست‌های HTTP پاسخ داده نمی‌شه.

رویدادهای پشتیبانی‌شده

رویداد زمان ارسال
message.created پیام جدیدی از مشتری دریافت یا به او ارسال شد
conversation.created مکالمه‌ی جدیدی شروع شد
conversation.assigned مکالمه به اپراتور یا تیم ارجاع داده شد
conversation.closed مکالمه بسته شد
customer.created مشتری جدیدی به سیستم اضافه شد
customer.updated اطلاعات مشتری تغییر کرد
customer.tag_added تگ جدیدی به مشتری اضافه شد
automation.triggered یک قانون اتوماسیون اجرا شد
ai.summary_created خلاصه‌ی AI برای مکالمه ساخته شد

ساختار Payload

هر درخواست Webhook یک بدنه‌ی JSON داره که ساختار کلی آن به این صورته:

{
    "event": "message.created",
    "timestamp": "2025-09-30T14:32:00Z",
    "id": "evt_abc123def456",
    "data": {
        ...
    }
}
فیلد توضیح
event نام رویداد
timestamp زمان وقوع (ISO 8601، UTC)
id شناسه‌ی یکتای رویداد (برای جلوگیری از تکرار)
data اطلاعات مربوط به رویداد

نمونه: message.created

{
    "event": "message.created",
    "timestamp": "2025-09-30T14:32:00Z",
    "id": "evt_abc123def456",
    "data": {
        "message_id": "msg_xyz789",
        "conversation_id": "conv_abc123",
        "sender_type": "customer",
        "content": "سلام، درباره پلن‌ها سوال داشتم",
        "channel": "whatsapp",
        "created_at": "2025-09-30T14:32:00Z",
        "customer": {
            "id": "cust_xyz789",
            "name": "مریم رضایی",
            "phone": "09123456789",
            "email": "maryam@example.com"
        },
        "conversation": {
            "id": "conv_abc123",
            "status": "open",
            "channel": "whatsapp",
            "assigned_to": null,
            "tags": ["سوال قیمت"]
        }
    }
}

نمونه: conversation.created

{
    "event": "conversation.created",
    "timestamp": "2025-09-30T14:30:00Z",
    "id": "evt_conv_def456",
    "data": {
        "conversation_id": "conv_abc123",
        "channel": "whatsapp",
        "status": "open",
        "customer": {
            "id": "cust_xyz789",
            "name": "مریم رضایی",
            "phone": "09123456789"
        },
        "first_message": "سلام، وقت بخیر",
        "created_at": "2025-09-30T14:30:00Z"
    }
}

نمونه: customer.created

{
    "event": "customer.created",
    "timestamp": "2025-09-30T14:30:00Z",
    "id": "evt_cust_ghi789",
    "data": {
        "customer_id": "cust_xyz789",
        "first_name": "مریم",
        "last_name": "رضایی",
        "phone": "09123456789",
        "email": "maryam@example.com",
        "status": "lead",
        "channel": "whatsapp",
        "created_at": "2025-09-30T14:30:00Z"
    }
}

هدرهای درخواست

هر درخواست Webhook این هدرها رو داره:

هدر توضیح
Content-Type application/json
User-Agent Shahoo-Webhook/1.0
X-Shahoo-Event نام رویداد
X-Shahoo-Delivery شناسه‌ی یکتای تحویل
X-Shahoo-Signature امضای HMAC-SHA256
X-Shahoo-Timestamp زمان ارسال (برای جلوگیری از replay attack)

احراز هویت با HMAC

برای اطمینان از اینکه درخواست واقعاً از طرف شاهو اومده، باید امضای X-Shahoo-Signature رو تأیید کنی.

روش تأیید

  1. بدنه‌ی درخواست خام (raw body) رو بردار
  2. با HMAC-SHA256 و Secret Key خودت امضا کن
  3. نتیجه رو با X-Shahoo-Signature مقایسه کن
  4. اگر مطابقت داشت، درخواست معتبره

نمونه پایتون

import hmac
import hashlib

def verify_signature(raw_body, signature, secret):
    expected = hmac.new(
        secret.encode('utf-8'),
        raw_body,
        hashlib.sha256
    ).hexdigest()

    return hmac.compare_digest(expected, signature)

نمونه Node.js

const crypto = require('crypto');

function verifySignature(rawBody, signature, secret) {
    const expected = crypto
        .createHmac('sha256', secret)
        .update(rawBody)
        .digest('hex');

    return crypto.timingSafeEqual(
        Buffer.from(expected),
        Buffer.from(signature)
    );
}

نمونه Django

import hmac
import hashlib
from django.http import HttpResponse

def webhook_view(request):
    signature = request.headers.get('X-Shahoo-Signature', '')
    secret = 'YOUR_WEBHOOK_SECRET'

    expected = hmac.new(
        secret.encode(),
        request.body,
        hashlib.sha256
    ).hexdigest()

    if not hmac.compare_digest(expected, signature):
        return HttpResponse(status=401)

    import json
    payload = json.loads(request.body)
    event = payload['event']

    if event == 'message.created':
        handle_new_message(payload['data'])
    elif event == 'conversation.created':
        handle_new_conversation(payload['data'])

    return HttpResponse(status=200)

پاسخ مورد انتظار

سرور تو باید با کد وضعیت 2xx پاسخ بده تا تحویل موفق تلقی بشه. اگر پاسخ با تأخیر یا خطا باشه:

وضعیت رفتار شاهو
2xx موفق — تحویل تمام
4xx خطای کلاینت — تلاش مجدد نمی‌شه
5xx خطای سرور — تلاش مجدد می‌شه
Timeout (بیشتر از ۱۰ ثانیه) تلاش مجدد می‌شه

زمان پاسخ

سرور تو باید در مدت ۱۰ ثانیه پاسخ بده. اگر طولانی‌تر شد، درخواست timeout می‌شه.

پیشنهاد: کارهای سنگین رو در صف (queue) قرار بده و سریع پاسخ بده. مثلاً به‌جای پردازش مستقیم، payload رو در Redis یا RabbitMQ بذار و بعداً پردازش کن.

تلاش مجدد خودکار

اگر سرور تو پاسخ نده یا خطای 5xx برگردونه، شاهو به‌صورت خودکار تلاش مجدد می‌کنه:

تلاش فاصله از تلاش قبلی
۱ (اصلی) بلافاصله
۲ ۳۰ ثانیه
۳ ۵ دقیقه
۴ ۳۰ دقیقه
۵ ۲ ساعت
۶ ۱۲ ساعت
۷ (آخر) ۲۴ ساعت

اگر بعد از ۷ تلاش هم موفق نشد، رویداد به‌عنوان failed علامت‌گذاری می‌شه و در پنل نمایش داده می‌شه.

جلوگیری از تکرار

چون ممکنه یک webhook چند بار برسه (به‌خاطر retry)، از فیلد id استفاده کن تا از پردازش تکراری جلوگیری کنی:

processed_events = set()

def handle_webhook(event_id, payload):
    if event_id in processed_events:
        return  # قبلاً پردازش شده

    processed_events.add(event_id)
    process(payload)

در محیط production، از Redis یا دیتابیس استفاده کن نه از حافظه‌ی محلی.

تست Webhook

در پنل، بخش تنظیمات ← اتصال‌ها ← Webhooks، می‌تونی یک رویداد تستی بفرستی:

  1. روی دکمه‌ی ارسال تست کنار Webhook کلیک کن
  2. نوع رویداد رو انتخاب کن
  3. شاهو یک payload نمونه به آدرس تو می‌فرسته
  4. پاسخ سرورت رو در لاگ می‌بینی

لاگ تحویل‌ها

در پنل، می‌تونی لیست تمام تحویل‌های Webhook رو ببینی:

  • زمان — چه زمانی ارسال شد
  • رویداد — نوع رویداد
  • وضعیت — موفق، خطا، در انتظار
  • کد پاسخ — از سرور تو
  • زمان پاسخ — میلی‌ثانیه
  • پاسخ — بدنه‌ی پاسخ سرور تو

لاگ‌ها به مدت ۳۰ روز نگهداری می‌شن.

نکات امنیتی

۱. همیشه امضا رو تأیید کن

حتی اگر HTTPS داری، حتماً امضای HMAC رو چک کن. این تضمین می‌کنه درخواست از طرف شاهو اومده.

۲. Timestamp رو چک کن

از X-Shahoo-Timestamp استفاده کن تا از replay attack جلوگیری کنی. اگر timestamp بیشتر از ۵ دقیقه قدیمی بود، درخواست رو رد کن.

from datetime import datetime, timezone, timedelta

def is_timestamp_valid(timestamp_str):
    event_time = datetime.fromisoformat(
        timestamp_str.replace('Z', '+00:00')
    )
    now = datetime.now(timezone.utc)

    diff = abs((now - event_time).total_seconds())
    return diff < 300  # 5 دقیقه

۳. Secret رو محرمانه نگه دار

Secret Key رو در متغیر محیطی ذخیره کن، نه در کد. اگر به‌اشتباه لو رفت، بلافاصله از پنل عوضش کن.

۴. آدرس Webhook رو عمومی نکن

اگر آدرس webhook تو در جای عمومی منتشر شده، ممکنه درخواست‌های جعلی دریافت کنی. یک مسیر یکتا و غیرقابل حدس انتخاب کن:

https://example.com/webhooks/shaoo/random-secret-path

مثال‌های کاربردی

ارسال پیام خوش‌آمد به مشتری جدید

def handle_customer_created(data):
    customer_id = data['customer_id']

    requests.post(
        'https://myshahoo.ir/api/v1/messages/send/',
        headers={'Authorization': f'Bearer {API_KEY}'},
        json={
            'customer_id': customer_id,
            'channel': 'whatsapp',
            'content': 'سلام! به شاهو خوش آمدید 👋'
        }
    )

افزودن مشتری به CRM خارجی

def handle_customer_created(data):
    requests.post(
        'https://my-crm.com/api/customers',
        headers={'X-API-Key': CRM_KEY},
        json={
            'name': f"{data['first_name']} {data['last_name']}",
            'phone': data['phone'],
            'email': data.get('email'),
            'source': 'shahoo'
        }
    )

اعلان به Slack هنگام پیام فوری

def handle_message_created(data):
    conversation = data['conversation']

    if 'فوری' in conversation.get('tags', []):
        requests.post(
            SLACK_WEBHOOK_URL,
            json={
                'text': f"🚨 پیام فوری از {data['customer']['name']}",
                'blocks': [{
                    'type': 'section',
                    'text': {
                        'type': 'mrkdwn',
                        'text': f"*{data['customer']['name']}*\n{data['content']}"
                    }
                }]
            }
        )

بهترین شیوه‌ها

  • همیشه سریع پاسخ بده — زیر ۱۰ ثانیه
  • از صف استفاده کن — پردازش سنگین رو جدا کن
  • Idempotent باشه — پردازش دوباره‌ی یک رویداد مشکلی ایجاد نکنه
  • امضا رو چک کن — برای امنیت
  • Timestamp رو تأیید کن — برای جلوگیری از replay
  • لاگ بگیر — برای دیباگ
  • Fail gracefully — اگر خطا داشتی، 2xx برگردون تا retry نکنه

قدم‌های بعدی

وبلاگ شاهو

آخرین یادداشت‌ها

داستان‌ها، تحلیل‌ها و درس‌هایی از ساخت شاهو.

استارتاپ و کسب و کار

راهنمای کامل راه‌اندازی فروشگاه اینترنتی در ایران (از صفر تا صد)

راه‌اندازی فروشگاه اینترنتی، پیچیده‌تر از یک سایت ساده است. در این مقاله گام‌به‌گام راه‌اندازی فروش…

ناشناس
4 دقیقه مطالعه
رشد فروش

راهنمای انتخاب CRM مناسب برای کسب‌وکارهای ایرانی

انتخاب CRM اشتباه، هزینه و زمان زیادی را هدر می‌دهد. در این مقاله معیارهای انتخاب CRM مناسب برای کس…

ناشناس
4 دقیقه مطالعه
پشتیبانی مشتریان

راهنمای کامل مدیریت ارتباط با مشتری در فروشگاه‌های آنلاین

فروشگاه‌های آنلاین بدون مدیریت ارتباط با مشتری، مشتری‌های خود را از دست می‌دهند. در این مقاله راهنم…

ناشناس
4 دقیقه مطالعه
بازاریابی ایمیلی حرفه‌ای با شاهو رشد فروش

راهنمای کامل بازاریابی ایمیلی در ایران (با وجود محدودیت‌ها)

ایمیل هنوز یکی از مؤثرترین کانال‌های بازاریابی است. در این مقاله یاد می‌گیرید چطور با وجود محدودیت‌…

ناشناس
4 دقیقه مطالعه
پشتیبانی مشتریان

راهنمای کامل مدیریت تیکت پشتیبانی در کسب‌وکارهای ایرانی

تیکت پشتیبانی، ستون فقرات پشتیبانی حرفه‌ای است. در این مقاله گام‌به‌گام مدیریت تیکت پشتیبانی را از …

ناشناس
4 دقیقه مطالعه
راهنمای کامل راه‌اندازی باشگاه مشتریان در ایران پشتیبانی مشتریان

راهنمای کامل راه‌اندازی باشگاه مشتریان در ایران

باشگاه مشتریان، مؤثرترین راه افزایش وفاداری و خرید دوباره است. در این مقاله گام‌به‌گام راه‌اندازی ب…

ناشناس
4 دقیقه مطالعه
راهنمای کامل مدیریت مکالمه‌های واتساپ برای کسب‌وکارها شبکه‌های اجتماعی

راهنمای کامل مدیریت مکالمه‌های واتساپ برای کسب‌وکارها

واتساپ، پرکاربردترین کانال ارتباطی کسب‌وکارهای ایرانی است. در این مقاله راهنمای کامل مدیریت حرفه‌ای…

ناشناس
4 دقیقه مطالعه
بازاریابی اینستاگرام با شاهو شبکه‌های اجتماعی

راهنمای جامع بازاریابی اینستاگرام برای کسب‌وکارهای ایرانی

اینستاگرام، مهم‌ترین کانال فروش کسب‌وکارهای ایرانی است. در این مقاله راهنمای کامل بازاریابی اینستاگ…

ناشناس
4 دقیقه مطالعه