# راهنمای اتصال CRM (MONTACT) به Montify — نسخه کامل v2 ## ۱. خلاصه و دیاگرام جریان این سند مشخصات اتصال سامانه **Montact CRM** به زیرسیستم‌های فروشگاهی (مانند Montify) را تعریف می‌کند. هر فروشگاه یک `Base URL` و یک `Token` اختصاصی دارد. ``` [فروشنده/Store] → [پنل Montify] → [صدور Token] → [سرور CRM] │ ▼ GET {Base URL}/montact/customers │ ▼ پاسخ JSON (لیست مشتریان) │ ▼ GET {Base URL}/montact/customers/:id/orders │ ▼ پاسخ JSON (سفارش‌های مشتری) ``` ## ۲. دریافت اطلاعات اتصال از فروشنده 1. فروشنده وارد پنل Montify می‌شود. 2. از مسیر «تنظیمات → یکپارچه‌سازی‌ها → CRM» وارد بخش Montact می‌شود. 3. دکمه «صدور Token» را می‌زند و مقادیر زیر را در اختیار تیم CRM قرار می‌دهد: | فیلد | مقدار نمونه | توضیح | |---|---|---| | Base URL | `https://store1.montify.com/api/v1` | آدرس پایه API فروشگاه | | Token | `mk_live_8f3a1c9d2e...` | توکن احراز هویت Bearer | | Store ID | `b2f1e4a0-...` | شناسه فروشگاه | > **نکته:** توکن‌ها می‌توانند منقضی شوند (`expires_at`). در صورت دریافت خطای ۴۰۱، باید توکن جدید از فروشنده درخواست شود. توکن هرگز نباید در فرانت‌اند ذخیره یا افشا شود؛ تنها باید در سرور CRM نگهداری گردد. ## ۳. احراز هویت تمام درخواست‌ها باید هدرهای زیر را داشته باشند: ```http Authorization: Bearer {Token} Content-Type: application/json Accept: application/json ``` ## ۴. فهرست کامل APIها | Method | Path | توضیح | |---|---|---| | GET | `/montact/customers` | لیست مشتریان (پشتیبانی از `page`, `limit`, `updated_after`) | | POST | `/montact/customers` | ثبت/همگام‌سازی مشتری از سمت CRM (اختیاری) | | GET | `/montact/customers/:id` | جزئیات کامل یک مشتری | | GET | `/montact/customers/:id/orders` | لیست سفارش‌های مشتری (پشتیبانی از `updated_after`) | | POST | `/montact/customers/:id/orders` | ثبت سفارش از CRM (اختیاری، در صورت فعال بودن) | | GET | `/montact/customers/:id/addresses` | لیست آدرس‌های مشتری | | GET | `/montact/customers/:id/transactions` | لیست تراکنش‌های مالی مشتری | | GET | `/montact/customers/:id/engagement` | داده‌های تعاملی (`saved`, `likes`, `comments`) | | GET | `/montact/orders/:orderId` | جزئیات یک سفارش خاص | | POST | `/montact/webhooks/register` | ثبت Webhook برای رویدادهای بلادرنگ (فاز ۳) | | GET | `/montact/webhooks/:id` | مشاهده جزئیات یک Webhook ثبت‌شده | | DELETE | `/montact/webhooks/:id` | حذف Webhook | > پارامتر `updated_after` یک مقدار ISO 8601 است (مثلاً `2026-07-01T00:00:00Z`) و فقط رکوردهای تغییر یافته بعد از آن زمان را برمی‌گرداند (برای Incremental Sync). ### نمونه‌های curl ```bash BASE="https://store1.montify.com/api/v1" TOKEN="mk_live_8f3a1c9d2e..." # لیست مشتریان curl -X GET "$BASE/montact/customers?page=1&limit=50" \ -H "Authorization: Bearer $TOKEN" \ -H "Accept: application/json" # لیست مشتریان تغییریافته بعد از یک زمان خاص (Incremental Sync) curl -X GET "$BASE/montact/customers?updated_after=2026-07-01T00:00:00Z" \ -H "Authorization: Bearer $TOKEN" # جزئیات یک مشتری curl -X GET "$BASE/montact/customers/123" \ -H "Authorization: Bearer $TOKEN" # سفارش‌های یک مشتری curl -X GET "$BASE/montact/customers/123/orders?updated_after=2026-07-01T00:00:00Z" \ -H "Authorization: Bearer $TOKEN" # آدرس‌های مشتری curl -X GET "$BASE/montact/customers/123/addresses" \ -H "Authorization: Bearer $TOKEN" # تراکنش‌های مشتری curl -X GET "$BASE/montact/customers/123/transactions" \ -H "Authorization: Bearer $TOKEN" # داده‌های تعاملی مشتری curl -X GET "$BASE/montact/customers/123/engagement" \ -H "Authorization: Bearer $TOKEN" # جزئیات یک سفارش خاص curl -X GET "$BASE/montact/orders/4567" \ -H "Authorization: Bearer $TOKEN" # ثبت Webhook (فاز ۳) curl -X POST "$BASE/montact/webhooks/register" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"url":"https://crm.montact.com/webhooks/montify","events":["order.created","order.paid"]}' ``` ## ۵. ساختار پاسخ کامل ### ۵.۱ فیلدهای مشتری (Customer) | فیلد | نوع | توضیح | |---|---|---| | id | integer | شناسه مشتری | | name | string | نام کامل | | first_name | string | نام | | last_name | string | نام خانوادگی | | phone | string | شماره موبایل | | email | string\|null | ایمیل | | username | string | نام کاربری | | avatar | string\|null | URL آواتار | | birthday | date\|null | تاریخ تولد | | gender | string\|null | جنسیت | | type | string | نوع مشتری (حقیقی/حقوقی) | | store_id | integer | شناسه فروشگاه | | created_at | datetime | تاریخ ایجاد | | updated_at | datetime | آخرین بروزرسانی | | description | string\|null | توضیحات | | bio | string\|null | بیوگرافی | | job | string\|null | شغل | | cash_balance | number | موجودی نقدی | | gold_balance | number | موجودی طلا (گرم) | | orders | array | لیست سفارش‌ها | | summary | object | خلاصه آماری مشتری | | addresses | array | لیست آدرس‌ها | | transactions | array | لیست تراکنش‌ها | | engagement | object | داده‌های تعاملی | ### ۵.۲ فیلدهای سفارش (Order) | فیلد | نوع | توضیح | |---|---|---| | id | integer | شناسه سفارش | | user_id | integer | شناسه مشتری | | store_id | integer | شناسه فروشگاه | | code | string | کد پیگیری سفارش | | sts | string | وضعیت سفارش | | payment_sts | string | وضعیت پرداخت | | payment_type | string | نوع پرداخت | | total_price | number | قیمت کل | | discount_total_price | number | قیمت پس از تخفیف | | total_discounts | number | مجموع تخفیف‌ها | | total_tax | number | مجموع مالیات | | total_qty | integer | تعداد کل اقلام | | profit | number | سود | | percent_profit | number | درصد سود | | sum_gold | number | مجموع وزن طلا | | sum_silver | number | مجموع وزن نقره | | address | object | آدرس ارسال | | address_id | integer | شناسه آدرس | | note | string\|null | یادداشت | | cancel_reason | string\|null | دلیل لغو | | cancelled_at | datetime\|null | تاریخ لغو | | closed_at | datetime\|null | تاریخ بستن سفارش | | transaction_id | integer\|null | شناسه تراکنش مرتبط | | code_discount | string\|null | کد تخفیف | | discount_code_id | integer\|null | شناسه کد تخفیف | | created_at | datetime | تاریخ ایجاد | | updated_at | datetime | آخرین بروزرسانی | | deleted_at | datetime\|null | تاریخ حذف نرم | | order_items | array | اقلام سفارش | | user | object | اطلاعات خلاصه مشتری | | store | object | اطلاعات خلاصه فروشگاه | ### ۵.۳ اقلام سفارش (Order Items) | فیلد | نوع | توضیح | |---|---|---| | id | integer | شناسه قلم سفارش | | order_id | integer | شناسه سفارش | | product_id | integer | شناسه محصول | | product_name | string | نام محصول | | qty | integer | تعداد | | price | number | قیمت واحد | | weight | number | وزن (گرم) | | total_price | number | قیمت کل قلم | ### ۵.۴ آدرس‌ها (Addresses) | فیلد | نوع | توضیح | |---|---|---| | id | integer | شناسه آدرس | | user_id | integer | شناسه مشتری | | province | string | استان | | city | string | شهر | | address | string | متن آدرس | | postal_code | string | کد پستی | | receiver_name | string | نام گیرنده | | receiver_phone | string | شماره گیرنده | | is_default | boolean | آدرس پیش‌فرض | ### ۵.۵ تراکنش‌ها (Transactions) | فیلد | نوع | توضیح | |---|---|---| | id | integer | شناسه تراکنش | | user_id | integer | شناسه مشتری | | type | string | نوع تراکنش (واریز/برداشت) | | amount | number | مقدار | | currency | string | واحد (ریال/گرم طلا) | | status | string | وضعیت تراکنش | | reference_code | string | کد پیگیری بانکی | | created_at | datetime | تاریخ ثبت | ### ۵.۶ داده‌های تعاملی (Engagement) مسیر: `GET /montact/customers/:id/engagement` ```json { "saved": [ { "product_id": 55, "product_name": "سکه بهار آزادی", "saved_at": "2026-06-10T11:22:00Z" } ], "likes": [ { "product_id": 78, "liked_at": "2026-06-15T09:00:00Z" } ], "comments": [ { "id": 301, "product_id": 78, "text": "کیفیت عالی بود", "rating": 5, "created_at": "2026-06-16T08:30:00Z" } ] } ``` ### ۵.۷ نمونه پاسخ JSON کامل لیست مشتریان ```json { "data": [ { "id": 123, "name": "علی رضایی", "first_name": "علی", "last_name": "رضایی", "phone": "09121234567", "email": "ali@example.com", "username": "ali_r", "avatar": "https://cdn.montify.com/avatars/123.png", "birthday": "1990-05-12", "gender": "male", "type": "individual", "store_id": 10, "created_at": "2025-01-10T08:00:00Z", "updated_at": "2026-07-01T10:15:00Z", "description": null, "bio": null, "job": "مهندس", "cash_balance": 1500000, "gold_balance": 2.35, "orders": [], "summary": { "total_orders": 12, "total_spent": 85000000 }, "addresses": [], "transactions": [], "engagement": { "saved": [], "likes": [], "comments": [] } } ], "meta": { "current_page": 1, "per_page": 50, "total": 532, "last_page": 11 } } ``` ## ۶. قوانین نگاشت پیشنهادی در CRM | فیلد Montify | فیلد معادل در CRM | |---|---| | id | external_customer_id | | name | full_name | | phone | mobile | | cash_balance | wallet_balance | | gold_balance | gold_wallet_balance | | orders[].code | order_reference | | orders[].sts | order_status | **استراتژی Sync گام به گام:** 1. دریافت لیست مشتریان صفحه‌بندی‌شده و Upsert در جدول مشتریان CRM بر اساس `id`. 2. برای هر مشتری، دریافت سفارش‌ها، آدرس‌ها و تراکنش‌ها به‌صورت جداگانه و Upsert در جداول مرتبط. 3. ذخیره `updated_at` هر رکورد برای استفاده در Sync افزایشی بعدی. ## ۷. استراتژی Sync سه‌فازی ### فاز ۱ — Polling ساده - فراخوانی دوره‌ای `/montact/customers` با `page` و `limit`. - فاصله پیشنهادی: هر ۵ تا ۱۵ دقیقه (بسته به حجم داده فروشگاه). - در صورت دریافت `429 Too Many Requests`، باید بر اساس هدر `Retry-After` صبر و تلاش مجدد شود. ### فاز ۲ — Incremental Sync - استفاده از `updated_after=` روی `/montact/customers` و `/montact/customers/:id/orders`. - CRM باید مقدار `last_sync_timestamp` را پس از هر Sync موفق ذخیره کند و در فراخوانی بعدی به‌عنوان `updated_after` ارسال کند. ```bash curl -X GET "$BASE/montact/customers?updated_after=2026-07-10T12:00:00Z" \ -H "Authorization: Bearer $TOKEN" ``` ### فاز ۳ — Webhook (Push-based، بلادرنگ) برای دریافت رویدادها بدون تأخیر Polling، CRM باید یک Endpoint عمومی HTTPS در اختیار Montify قرار دهد: ```bash curl -X POST "$BASE/montact/webhooks/register" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "url": "https://crm.montact.com/webhooks/montify", "events": ["customer.created", "customer.updated", "order.created", "order.updated", "order.paid", "order.cancelled"] }' ``` **رویدادهای پشتیبانی‌شده:** | رویداد | توضیح | |---|---| | customer.created | ایجاد مشتری جدید | | customer.updated | بروزرسانی اطلاعات مشتری | | order.created | ثبت سفارش جدید | | order.updated | تغییر در سفارش | | order.paid | پرداخت سفارش | | order.cancelled | لغو سفارش | **نمونه Payload برای `order.created`:** ```json { "event": "order.created", "delivery_id": "d2f1c9e0-84a3-4b7f-9c1e-3a2b1c0d9e8f", "store_id": 10, "data": { "id": 4567, "user_id": 123, "code": "ORD-2026-4567", "sts": "pending", "payment_sts": "unpaid", "total_price": 12500000, "total_qty": 2, "created_at": "2026-07-10T12:05:00Z" } } ``` **هدرهای ارسالی Webhook:** ```http X-Montact-Signature: sha256=3b4f9a1c7e8d2f... X-Montact-Event: order.created X-Montact-Delivery-Id: d2f1c9e0-84a3-4b7f-9c1e-3a2b1c0d9e8f Content-Type: application/json ``` **وریفای امضا (Node.js):** ```javascript const crypto = require('crypto'); function verifySignature(rawBody, signatureHeader, secret) { const expected = crypto .createHmac('sha256', secret) .update(rawBody) .digest('hex'); const received = signatureHeader.replace('sha256=', ''); return crypto.timingSafeEqual( Buffer.from(expected, 'hex'), Buffer.from(received, 'hex') ); } ``` **Retry Policy:** - در صورت عدم دریافت پاسخ `2xx` ظرف ۱۰ ثانیه، تلاش مجدد با backoff نمایی انجام می‌شود. - فاصله تلاش‌ها: `1s → 5s → 15s → 60s → 300s` (حداکثر ۵ بار). - CRM باید سریعاً `200 OK` برگرداند و پردازش سنگین را به‌صورت async انجام دهد. - Idempotency بر اساس `X-Montact-Delivery-Id` باید رعایت شود تا پردازش تکراری رخ ندهد. ## ۸. کدهای خطا | کد HTTP | معنی | اقدام پیشنهادی | |---|---|---| | 200 | موفق | - | | 400 | درخواست نامعتبر | بررسی پارامترها | | 401 | توکن نامعتبر یا منقضی | درخواست توکن جدید از فروشنده | | 403 | عدم دسترسی به منبع | بررسی scope توکن | | 404 | منبع یافت نشد | بررسی شناسه ارسالی | | 429 | تعداد درخواست بیش از حد مجاز | توجه به هدر `Retry-After` و کاهش نرخ درخواست | | 500 | خطای سرور | تلاش مجدد بعد از فاصله زمانی | ## ۹. محدودیت‌ها و رفتار فعلی - API برای داده‌های اصلی (مشتری، سفارش، آدرس، تراکنش) صرفاً **خواندنی (Read-only)** است؛ تنها استثنا ثبت/حذف Webhook است. - فیلدهای حساس (مانند رمز عبور، هش‌های داخلی) از پاسخ‌ها حذف شده‌اند. - CORS برای دامنه‌های مجاز CRM فعال است. - نرخ مجاز درخواست پیشنهادی: **۱۰۰ درخواست در دقیقه به ازای هر Token**. ## ۱۰. چک‌لیست اتصال برنامه‌نویس CRM - [ ] دریافت `Base URL`، `Token` و `Store ID` از فروشنده - [ ] تست احراز هویت با `GET /montact/customers` - [ ] پیاده‌سازی Polling فاز ۱ - [ ] پیاده‌سازی Incremental Sync با `updated_after` (فاز ۲) - [ ] ثبت Webhook Endpoint و تست دریافت رویداد (فاز ۳) - [ ] پیاده‌سازی وریفای امضای HMAC-SHA256 - [ ] تست Idempotency بر اساس `X-Montact-Delivery-Id` - [ ] مدیریت خطاهای ۴۰۱/۴۲۹ و Retry مناسب - [ ] ذخیره امن Token در سمت سرور (نه فرانت‌اند) ## ۱۱. پشتیبانی برای ارسال تیکت پشتیبانی، اطلاعات زیر لازم است: - `Store ID` - زمان دقیق درخواست (UTC) - کد خطای دریافتی - `X-Montact-Delivery-Id` (در صورت مرتبط بودن به Webhook) - نمونه Request/Response (بدون افشای Token کامل)