Files
Ho Ngoc Hai 76d75c753b Migrate
2026-05-23 18:37:02 +07:00

13 KiB

API Documentation

Service: mkt-whatsapp-service-net
Version: v1.0
Base URL: /api/v1/whatsapp

Authentication

All endpoints (except webhooks) require authentication via JWT token.

Authorization: Bearer <jwt_token>

Response Format

All responses follow this structure:

{
  "success": true | false,
  "data": { ... },
  "error": "Error message" | null,
  "pagination": { ... } | null
}

Webhooks

Verify Webhook

GET /webhooks

WhatsApp verification challenge.

Query Parameters:

  • hub.mode (string) - Should be "subscribe"
  • hub.verify_token (string) - Your verification token
  • hub.challenge (string) - Random string to echo back

Response:

(Plain text) hub.challenge value

Receive Events

POST /webhooks

Receive message events from WhatsApp.

Headers:

  • X-Hub-Signature-256 - HMAC-SHA256 signature

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": "Hello"
          }
        }]
      }
    }]
  }]
}

Response:

{
  "success": true
}

WhatsApp Accounts

Connect Account

POST /accounts

Connect a WhatsApp Business Account.

Request:

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

Response:

{
  "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"
  }
}

Get Account

GET /accounts/{shopId}

Get account details for a shop.

Response:

{
  "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"
  }
}

Disconnect Account

DELETE /accounts/{shopId}

Disconnect WhatsApp Business Account.

Response:

{
  "success": true,
  "data": {
    "message": "Account disconnected successfully"
  }
}

Conversations

List Conversations

GET /conversations

Get paginated list of conversations.

Query Parameters:

  • shopId (required) - Shop ID
  • status (optional) - Filter: active, closed, expired
  • assignedAgentId (optional) - Filter by agent
  • skip (default: 0) - Pagination offset
  • take (default: 20, max: 100) - Page size

Response:

{
  "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
  }
}

Get Conversation

GET /conversations/{conversationId}

Get conversation details with messages.

Response:

{
  "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"
  }
}

Send Message

POST /conversations/{conversationId}/messages

Send a message in a conversation.

Request:

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

Response:

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

Media Message:

{
  "content": {
    "type": "image",
    "url": "https://example.com/product.jpg",
    "caption": "Check out this product!"
  }
}

Interactive Message:

{
  "content": {
    "type": "interactive",
    "interactive": {
      "type": "button",
      "body": {
        "text": "Choose an option:"
      },
      "action": {
        "buttons": [
          {"id": "yes", "title": "Yes"},
          {"id": "no", "title": "No"}
        ]
      }
    }
  }
}

Assign Conversation

POST /conversations/{conversationId}/assign

Assign conversation to an agent.

Request:

{
  "agentId": "agent-001"
}

Response:

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

Close Conversation

POST /conversations/{conversationId}/close

Close a conversation.

Response:

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

Customers

List Customers

GET /customers

Get paginated customer list.

Query Parameters:

  • shopId (required)
  • search (optional) - Search by name/phone
  • tags (optional) - Filter by tags (comma-separated)
  • skip / take (pagination)

Response:

{
  "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
  }
}

Get Customer

GET /customers/{waId}

Get customer profile.

Query Parameters:

  • shopId (required)

Response:

{
  "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"
    }
  }
}

Update Customer Tags

PUT /customers/{waId}/tags

Add or remove customer tags.

Query Parameters:

  • shopId (required)

Request:

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

Response:

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

Update Opt-In Status

PUT /customers/{waId}/opt-in

Update customer consent.

Request:

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

Response:

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

Automation Flows

List Flows

GET /flows

Get automation flows.

Query Parameters:

  • shopId (required)
  • isActive (optional) - Filter by status

Response:

{
  "success": true,
  "data": {
    "flows": [
      {
        "id": "flow-001",
        "flowName": "Welcome New Customer",
        "triggerType": "keyword",
        "isActive": true,
        "executionCount": 523,
        "createdAt": "2026-01-10T00:00:00Z"
      }
    ]
  }
}

Create Flow

POST /flows

Create automation flow.

Request: See Automation Guide

Response:

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

Update Flow

PUT /flows/{flowId}

Update flow configuration.

Activate Flow

POST /flows/{flowId}/activate

Enable automation flow.

Deactivate Flow

POST /flows/{flowId}/deactivate

Disable automation flow.


AI Agents

Create AI Agent

POST /ai-agents

Configure AI chatbot.

Request: See AI Chatbot Guide

Update AI Agent

PUT /ai-agents/{agentId}

Update personality/prompts.

Activate AI Agent

POST /ai-agents/{agentId}/activate

Enable AI responses.

Test AI Agent

POST /ai-agents/{agentId}/test

Simulate AI response.

Request:

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

Response:

{
  "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
  }
}

Analytics

Message Statistics

GET /analytics/messages

Get message volume metrics.

Query Parameters:

  • shopId (required)
  • startDate / endDate (ISO 8601)
  • groupBy - hour, day, week

Response:

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

Conversation Metrics

GET /analytics/conversations

Get conversation performance metrics.

Response:

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

Automation Performance

GET /analytics/automations

Get automation flow execution stats.

Response:

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

Error Codes

Code Message Description
400 Bad Request Invalid request format
401 Unauthorized Missing or invalid auth token
404 Not Found Resource doesn't exist
409 Conflict Duplicate resource
422 Validation Error Business rule violation
429 Rate Limit Exceeded Too many requests
500 Internal Server Error Server error

Error Response Format:

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

Rate Limits

  • Public APIs: 60 requests/minute per shop
  • Webhooks: No limit (but must respond < 5s)
  • Analytics: 10 requests/minute per shop

Webhooks Signature Verification

Verify X-Hub-Signature-256 header:

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');
}

Pagination

All list endpoints support pagination:

Request:

GET /conversations?skip=20&take=20

Response:

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

Changelog

v1.0 (2026-01-18)

  • Initial release
  • WhatsApp Cloud API integration
  • Automation flows
  • AI chatbot
  • Customer management