Files
pos-system/services/mkt-whatsapp-service-net/docs/vi/API.md

14 KiB

Tài Liệu API

Dịch vụ: mkt-whatsapp-service-net
Phiên bản: v1.0
URL Cơ sở: /api/v1/whatsapp

Xác Thực

Tất cả endpoints (trừ webhooks) yêu cầu xác thực qua JWT token.

Authorization: Bearer <jwt_token>

Định Dạng Phản Hồi

Tất cả phản hồi tuân theo cấu trúc này:

{
  "success": true | false,
  "data": { ... },
  "error": "Thông báo lỗi" | null,
  "pagination": { ... } | null
}

Webhooks

Xác Minh Webhook

GET /webhooks

Xác minh thách thức từ WhatsApp.

Tham Số Truy Vấn:

  • hub.mode (string) - Phải là "subscribe"
  • hub.verify_token (string) - Token xác minh của bạn
  • hub.challenge (string) - Chuỗi ngẫu nhiên để phản hồi lại

Phản Hồi:

(Plain text) giá trị hub.challenge

Nhận Sự Kiện

POST /webhooks

Nhận sự kiện tin nhắn từ WhatsApp.

Headers:

  • X-Hub-Signature-256 - Chữ ký HMAC-SHA256

Request Body:

{
  "object": "whatsapp_business_account",
  "entry": [{
    "id": "123456",
    "changes": [{
      "value": {
        "messaging_product": "whatsapp",
        "metadata": {
          "phone_number_id": "123456789"
        },
        "messages": [{
          "from": "84901234567",
          "id": "wamid.xxx",
          "timestamp": "1704000000",
          "type": "text",
          "text": {
            "body": "Xin chào"
          }
        }]
      }
    }]
  }]
}

Phản Hồi:

{
  "success": true
}

Tài Khoản WhatsApp

Kết Nối Tài Khoản

POST /accounts

Kết nối Tài Khoản Doanh Nghiệp WhatsApp.

Request:

{
  "shopId": "550e8400-e29b-41d4-a716-446655440000",
  "phoneNumberId": "123456789",
  "accessToken": "EAAxxxxx",
  "webhookUrl": "https://yourdomain.com/api/v1/whatsapp/webhooks"
}

Phản Hồi:

{
  "success": true,
  "data": {
    "accountId": "660e8400-e29b-41d4-a716-446655440000",
    "shopId": "550e8400-e29b-41d4-a716-446655440000",
    "phoneNumberId": "123456789",
    "status": "active",
    "messageTier": "tier_1",
    "connectedAt": "2026-01-18T10:00:00Z"
  }
}

Lấy Thông Tin Tài Khoản

GET /accounts/{shopId}

Lấy thông tin tài khoản của cửa hàng.

Phản Hồi:

{
  "success": true,
  "data": {
    "accountId": "660e8400-e29b-41d4-a716-446655440000",
    "shopId": "550e8400-e29b-41d4-a716-446655440000",
    "phoneNumberId": "123456789",
    "webhookUrl": "https://yourdomain.com/api/v1/whatsapp/webhooks",
    "status": "active",
    "messageTier": "tier_2",
    "dailyLimit": 10000,
    "messagesUsedToday": 1523,
    "connectedAt": "2026-01-15T10:00:00Z"
  }
}

Ngắt Kết Nối Tài Khoản

DELETE /accounts/{shopId}

Ngắt kết nối Tài Khoản Doanh Nghiệp WhatsApp.

Phản Hồi:

{
  "success": true,
  "data": {
    "message": "Ngắt kết nối tài khoản thành công"
  }
}

Hội Thoại

Danh Sách Hội Thoại

GET /conversations

Lấy danh sách hội thoại có phân trang.

Tham Số Truy Vấn:

  • shopId (bắt buộc) - ID cửa hàng
  • status (tùy chọn) - Lọc: active, closed, expired
  • assignedAgentId (tùy chọn) - Lọc theo nhân viên
  • skip (mặc định: 0) - Vị trí phân trang
  • take (mặc định: 20, tối đa: 100) - Kích thước trang

Phản Hồi:

{
  "success": true,
  "data": {
    "conversations": [
      {
        "id": "conv-001",
        "shopId": "shop-001",
        "customerWaId": "84901234567",
        "customerName": "Nguyễn Văn A",
        "status": "active",
        "assignedAgentId": null,
        "lastMessageAt": "2026-01-18T10:30:00Z",
        "messageCount": 5,
        "tags": ["new-customer"],
        "createdAt": "2026-01-18T10:00:00Z"
      }
    ],
    "totalCount": 42
  },
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 42,
    "totalPages": 3
  }
}

Lấy Thông Tin Hội Thoại

GET /conversations/{conversationId}

Lấy chi tiết hội thoại với tin nhắn.

Phản Hồi:

{
  "success": true,
  "data": {
    "id": "conv-001",
    "shopId": "shop-001",
    "customer": {
      "waId": "84901234567",
      "name": "Nguyễn Văn A",
      "tags": ["vip"]
    },
    "status": "active",
    "messages": [
      {
        "id": "msg-001",
        "whatsAppMessageId": "wamid.xxx",
        "direction": "inbound",
        "content": {
          "type": "text",
          "text": "Xin chào"
        },
        "status": "read",
        "timestamp": "2026-01-18T10:00:00Z"
      },
      {
        "id": "msg-002",
        "whatsAppMessageId": "wamid.yyy",
        "direction": "outbound",
        "content": {
          "type": "text",
          "text": "Xin chào! Chúng tôi có thể giúp gì cho bạn?"
        },
        "status": "delivered",
        "timestamp": "2026-01-18T10:00:15Z"
      }
    ],
    "createdAt": "2026-01-18T10:00:00Z",
    "expiresAt": "2026-01-19T10:00:00Z"
  }
}

Gửi Tin Nhắn

POST /conversations/{conversationId}/messages

Gửi tin nhắn trong hội thoại.

Request:

{
  "content": {
    "type": "text",
    "text": "Cảm ơn bạn đã liên hệ!"
  }
}

Phản Hồi:

{
  "success": true,
  "data": {
    "messageId": "msg-003",
    "whatsAppMessageId": "wamid.zzz",
    "status": "sent",
    "timestamp": "2026-01-18T10:05:00Z"
  }
}

Tin Nhắn Media:

{
  "content": {
    "type": "image",
    "url": "https://example.com/product.jpg",
    "caption": "Xem sản phẩm này!"
  }
}

Tin Nhắn Tương Tác:

{
  "content": {
    "type": "interactive",
    "interactive": {
      "type": "button",
      "body": {
        "text": "Chọn một tùy chọn:"
      },
      "action": {
        "buttons": [
          {"id": "yes", "title": "Có"},
          {"id": "no", "title": "Không"}
        ]
      }
    }
  }
}

Gán Hội Thoại

POST /conversations/{conversationId}/assign

Gán hội thoại cho nhân viên.

Request:

{
  "agentId": "agent-001"
}

Phản Hồi:

{
  "success": true,
  "data": {
    "conversationId": "conv-001",
    "assignedAgentId": "agent-001",
    "assignedAt": "2026-01-18T10:10:00Z"
  }
}

Đóng Hội Thoại

POST /conversations/{conversationId}/close

Đóng hội thoại.

Phản Hồi:

{
  "success": true,
  "data": {
    "conversationId": "conv-001",
    "status": "closed",
    "closedAt": "2026-01-18T10:15:00Z"
  }
}

Khách Hàng

Danh Sách Khách Hàng

GET /customers

Lấy danh sách khách hàng có phân trang.

Tham Số Truy Vấn:

  • shopId (bắt buộc)
  • search (tùy chọn) - Tìm kiếm theo tên/số điện thoại
  • tags (tùy chọn) - Lọc theo tags (phân cách bằng dấu phẩy)
  • skip / take (phân trang)

Phản Hồi:

{
  "success": true,
  "data": {
    "customers": [
      {
        "id": "cust-001",
        "waId": "84901234567",
        "name": "Nguyễn Văn A",
        "tags": ["vip", "frequent-buyer"],
        "optInStatus": "opted_in",
        "conversationCount": 12,
        "lastContactedAt": "2026-01-18T10:00:00Z",
        "createdAt": "2026-01-01T00:00:00Z"
      }
    ],
    "totalCount": 150
  }
}

Lấy Thông Tin Khách Hàng

GET /customers/{waId}

Lấy hồ sơ khách hàng.

Tham Số Truy Vấn:

  • shopId (bắt buộc)

Phản Hồi:

{
  "success": true,
  "data": {
    "id": "cust-001",
    "waId": "84901234567",
    "shopId": "shop-001",
    "name": "Nguyễn Văn A",
    "profilePictureUrl": "https://...",
    "consent": {
      "status": "opted_in",
      "timestamp": "2026-01-01T10:00:00Z",
      "source": "whatsapp"
    },
    "tags": ["vip"],
    "customFields": {
      "city": "Hanoi",
      "preferredLanguage": "vi"
    },
    "stats": {
      "conversationCount": 12,
      "averageResponseTime": "5m",
      "lastPurchaseDate": "2026-01-15"
    }
  }
}

Cập Nhật Tags Khách Hàng

PUT /customers/{waId}/tags

Thêm hoặc xóa tags khách hàng.

Tham Số Truy Vấn:

  • shopId (bắt buộc)

Request:

{
  "addTags": ["vip", "electronics-buyer"],
  "removeTags": ["new-customer"]
}

Phản Hồi:

{
  "success": true,
  "data": {
    "waId": "84901234567",
    "tags": ["vip", "electronics-buyer"]
  }
}

Cập Nhật Trạng Thái Opt-In

PUT /customers/{waId}/opt-in

Cập nhật sự đồng ý của khách hàng.

Request:

{
  "status": "opted_in",
  "source": "web"
}

Phản Hồi:

{
  "success": true,
  "data": {
    "waId": "84901234567",
    "consent": {
      "status": "opted_in",
      "timestamp": "2026-01-18T10:20:00Z",
      "source": "web"
    }
  }
}

Luồng Tự Động

Danh Sách Luồng

GET /flows

Lấy danh sách luồng tự động.

Tham Số Truy Vấn:

  • shopId (bắt buộc)
  • isActive (tùy chọn) - Lọc theo trạng thái

Phản Hồi:

{
  "success": true,
  "data": {
    "flows": [
      {
        "id": "flow-001",
        "flowName": "Chào Mừng Khách Hàng Mới",
        "triggerType": "keyword",
        "isActive": true,
        "executionCount": 523,
        "createdAt": "2026-01-10T00:00:00Z"
      }
    ]
  }
}

Tạo Luồng

POST /flows

Tạo luồng tự động.

Request: Xem Hướng Dẫn Tự Động

Phản Hồi:

{
  "success": true,
  "data": {
    "flowId": "flow-002",
    "flowName": "FAQ Bot",
    "isActive": false
  }
}

Cập Nhật Luồng

PUT /flows/{flowId}

Cập nhật cấu hình luồng.

Kích Hoạt Luồng

POST /flows/{flowId}/activate

Bật luồng tự động.

Vô Hiệu Hóa Luồng

POST /flows/{flowId}/deactivate

Tắt luồng tự động.


AI Agents

Tạo AI Agent

POST /ai-agents

Cấu hình chatbot AI.

Request: Xem Hướng Dẫn AI Chatbot

Cập Nhật AI Agent

PUT /ai-agents/{agentId}

Cập nhật tính cách/prompts.

Kích Hoạt AI Agent

POST /ai-agents/{agentId}/activate

Bật phản hồi AI.

Kiểm Tra AI Agent

POST /ai-agents/{agentId}/test

Mô phỏng phản hồi AI.

Request:

{
  "conversationHistory": [
    {"role": "user", "content": "Bạn có laptop nào tốt?"}
  ],
  "customerContext": {
    "name": "Nguyễn Văn A",
    "tags": ["vip"]
  }
}

Phản Hồi:

{
  "success": true,
  "data": {
    "generatedResponse": "Chúng tôi có nhiều laptop tuyệt vời! Bạn đang tìm laptop cho mục đích gì ạ? Gaming hay làm việc văn phòng?",
    "tokensUsed": {"prompt": 450, "completion": 120, "total": 570},
    "estimatedCost": 0.0154,
    "latencyMs": 1850
  }
}

Phân Tích

Thống Kê Tin Nhắn

GET /analytics/messages

Lấy số liệu về lượng tin nhắn.

Tham Số Truy Vấn:

  • shopId (bắt buộc)
  • startDate / endDate (ISO 8601)
  • groupBy - hour, day, week

Phản Hồi:

{
  "success": true,
  "data": {
    "metrics": [
      {
        "date": "2026-01-18",
        "inboundCount": 245,
        "outboundCount": 298,
        "totalCount": 543
      }
    ],
    "summary": {
      "totalInbound": 2450,
      "totalOutbound": 2980,
      "averagePerDay": 543
    }
  }
}

Số Liệu Hội Thoại

GET /analytics/conversations

Lấy số liệu hiệu suất hội thoại.

Phản Hồi:

{
  "success": true,
  "data": {
    "averageResponseTime": "2m 30s",
    "averageResolutionTime": "15m 45s",
    "automationResolutionRate": 0.65,
    "aiResolutionRate": 0.78,
    "humanHandoffRate": 0.22
  }
}

Hiệu Suất Tự Động

GET /analytics/automations

Lấy thống kê thực thi luồng tự động.

Phản Hồi:

{
  "success": true,
  "data": {
    "flows": [
      {
        "flowId": "flow-001",
        "flowName": "Welcome Bot",
        "executionCount": 523,
        "completionRate": 0.89,
        "averageSteps": 3.2,
        "fallbackRate": 0.11
      }
    ]
  }
}

Mã Lỗi

Thông Báo Mô Tả
400 Bad Request Định dạng request không hợp lệ
401 Unauthorized Thiếu hoặc token xác thực không hợp lệ
404 Not Found Tài nguyên không tồn tại
409 Conflict Tài nguyên trùng lặp
422 Validation Error Vi phạm quy tắc nghiệp vụ
429 Rate Limit Exceeded Quá nhiều yêu cầu
500 Internal Server Error Lỗi máy chủ

Định Dạng Phản Hồi Lỗi:

{
  "success": false,
  "error": "Validation failed: Phone number is required",
  "details": {
    "field": "phoneNumberId",
    "code": "REQUIRED_FIELD"
  }
}

Giới Hạn Tốc Độ

  • Public APIs: 60 yêu cầu/phút mỗi cửa hàng
  • Webhooks: Không giới hạn (nhưng phải phản hồi < 5s)
  • Analytics: 10 yêu cầu/phút mỗi cửa hàng

Xác Minh Chữ Ký Webhooks

Xác minh header X-Hub-Signature-256:

const crypto = require('crypto');

const signature = req.headers['x-hub-signature-256'];
const payload = JSON.stringify(req.body);

const expectedSignature = 'sha256=' + 
  crypto.createHmac('sha256', APP_SECRET)
    .update(payload)
    .digest('hex');

if (signature !== expectedSignature) {
  throw new Error('Invalid signature');
}

Phân Trang

Tất cả endpoints danh sách đều hỗ trợ phân trang:

Request:

GET /conversations?skip=20&take=20

Phản Hồi:

{
  "pagination": {
    "page": 2,
    "limit": 20,
    "total": 150,
    "totalPages": 8
  }
}

Changelog

v1.0 (2026-01-18)

  • Phát hành ban đầu
  • Tích hợp WhatsApp Cloud API
  • Luồng tự động
  • AI chatbot
  • Quản lý khách hàng