Hoang  Kim

Hoang Kim

1658842095

Xây Dựng ứng Dụng Thương Mại điện Tử Tự động Với WhatsApp Cloud API

Vào tháng 5 năm 2022, Meta (công ty trước đây được gọi là Facebook, sở hữu WhatsApp) thông báo rằng họ sẽ mở rộng API kinh doanh WhatsApp cho công chúng. Bài viết này dự định chào mừng bạn đến với thế giới cơ hội của Meta, nơi chatbot WhatsApp có thể giúp bạn tạo khách hàng tiềm năng, nhận đơn đặt hàng, lên lịch cuộc hẹn, chạy khảo sát, lấy ý kiến ​​phản hồi của khách hàng, cung cấp hỗ trợ khách hàng có thể mở rộng, gửi hóa đơn và biên nhận, v.v.

Hướng dẫn này sẽ đi sâu vào các phần kỹ thuật của việc xây dựng một chatbot WhatsApp từ đầu.

Đến cuối hướng dẫn này, bạn sẽ tạo được chatbot WhatsApp của riêng mình.

Hướng dẫn của chúng tôi tập trung vào một cửa hàng thương mại điện tử đơn giản dành cho mẹ và người mua bán các mặt hàng gia dụng và thời trang nhanh. Doanh nghiệp sẽ có một chatbot WhatsApp, nơi khách hàng có thể duyệt và mua từ cửa hàng thương mại điện tử.

Mọi cửa hàng thương mại điện tử đều cần sản phẩm (giá cả, tên, mô tả, v.v.) và đối với hướng dẫn này, chúng tôi sẽ sử dụng các sản phẩm giả từ FakeStoreAPI .

Điều kiện tiên quyết

Trước khi chúng tôi tiếp tục, bài viết này giả định rằng:

  • Bạn có tài khoản nhà phát triển Meta hợp lệ. Nếu bạn không, vui lòng xem https://developers.facebook.com/
  • Bạn am hiểu về JavaScript và Node.js
  • Bạn đã cài đặt ngrok

Bước 1: Định cấu hình ứng dụng của chúng tôi trên bảng điều khiển Meta Developer

Bước đầu tiên để sử dụng bất kỳ API nào của Meta là tạo một ứng dụng trên Meta dashboard, điều này hoàn toàn miễn phí.

  • Trong khi đăng nhập vào tài khoản nhà phát triển Meta của bạn, hãy điều hướng đến https://developers.facebook.com/apps
  • Nhấp vào Tạo ứng dụng
  • Trong màn hình tiếp theo, hãy chọn loại ứng dụng Doanh nghiệp

Chọn loại ứng dụng kinh doanh

  • Tiếp theo, điền tên ứng dụng và địa chỉ email của bạn, sau đó chọn trang / doanh nghiệp bạn muốn liên kết với ứng dụng này

Đặt tên ứng dụng và chọn trang được liên kết với nó

  • Sau khi gửi biểu mẫu, bạn sẽ được dẫn đến một màn hình như sau:

Chọn thiết lập WhatsApp

Trên màn hình này, chọn WhatsApp và nhấp vào nút Thiết lập của nó .

Sau đó, bạn sẽ được dẫn đến một màn hình mới, như hình dưới đây.

Trang bắt đầu

Trên màn hình này, hãy lưu ý:

  • ID ứng dụng , là ID được liên kết với ứng dụng Meta của chúng tôi. Của tôi là1184643492312754
  • thông báo truy cập tạm thời , sẽ hết hạn sau 24 giờ. Của tôi bắt đầu bằng EAAQ1bU6LdrIBA
  • Số điện thoại Kiểm tra mà chúng tôi sẽ sử dụng để gửi tin nhắn cho khách hàng. Của tôi là+1 555 025 3483
    • ID số điện thoại . Của tôi là113362588047543
    • ID tài khoản doanh nghiệp WhatsApp . Của tôi là102432872486730

Xin lưu ý rằng mã thông báo truy cập tạm thời sẽ hết hạn sau 24 giờ, tại thời điểm đó chúng tôi cần phải gia hạn mã này. Khi chuyển ứng dụng của mình sang chế độ trực tiếp, bạn có thể đăng ký mã thông báo truy cập vĩnh viễn mà chúng tôi không cần thực hiện vì ứng dụng của chúng tôi đang ở chế độ phát triển.

ID số điện thoại và ID tài khoản doanh nghiệp WhatsApp được gắn với số điện thoại thử nghiệm.

Tiếp theo, hãy thêm một số điện thoại để sử dụng để nhận tin nhắn.

Trong chế độ phát triển, Meta giới hạn chúng tôi ở năm số người nhận vì lý do để ngăn chặn thư rác / lạm dụng. Ở chế độ trực tiếp / sản xuất, số đại diện cho số điện thoại của khách hàng của chúng tôi.

Nhấp vào Chọn số điện thoại người nhận và thêm số WhatsApp của riêng bạn, như được hiển thị trong ảnh chụp màn hình bên dưới:

Thêm hộp thoại số điện thoại người nhận

Sau khi thêm số người nhận, bạn sẽ thấy một màn hình giống như bên dưới. Nếu đây là lần đầu tiên bạn thêm số điện thoại của mình vào các nền tảng Meta - chẳng hạn như Trang Facebook, bộ Meta Business hoặc bảng điều khiển dành cho nhà phát triển Meta - bạn sẽ nhận được thông báo OTP từ Facebook Business nhắc bạn xác minh rằng bạn thực sự sở hữu số người nhận .

Gửi tin nhắn bằng API

Kiểm tra thiết lập của chúng tôi

Hãy kiểm tra xem mọi thứ cho đến bước này có hoạt động tốt không. Chúng tôi sẽ thực hiện việc này bằng cách nhấp vào nút Gửi tin nhắn .

Nếu mọi thứ đều ổn, bạn sẽ thấy một tin nhắn trong hộp thư đến WhatsApp từ số kiểm tra của mình.

Tin nhắn Hello World từ Facebook trong hộp thư đến WhatsApp

Cho đến thời điểm này, chúng tôi đang làm tốt! Hãy tạm dừng và mở trình chỉnh sửa mã của bạn. Đừng đóng tab trình duyệt của bạn vì chúng tôi sẽ quay lại trang tổng quan Nhà phát triển Meta sau vài phút.

Bước 2: Thiết lập webhook để nhận tin nhắn

Bây giờ thiết lập của chúng ta có thể gửi tin nhắn thành công, hãy thiết lập cách nhận tin nhắn. Đã đến lúc chúng ta phải làm bẩn tay và đắm mình trong việc viết mã. Tất cả mã chúng tôi sẽ viết cho hướng dẫn này đều nằm trong kho lưu trữ GitHub này .

Tạo một thư mục mới để chứa dự án của chúng tôi. Mở thư mục này trong một thiết bị đầu cuối và chạy tập lệnh dưới đây:

npm init ---yes

Tiếp theo, chúng tôi cài đặt một số gói:

npm install express pdfkit request whatsappcloudapi_wrapper
npm install nodemon --dev

Dưới đây là giải thích ngắn gọn về từng loại:

  • Gói expressnày rất quan trọng để thiết lập máy chủ của chúng tôi. Máy chủ sẽ chứa một tuyến đường sẽ hoạt động như một webhook của chúng tôi
  • Gói pdfkitnày sẽ được sử dụng để tạo hóa đơn cho khách hàng của chúng tôi khi họ thanh toán
  • Gói request này sẽ giúp chúng tôi chạy các yêu cầu tìm nạp tới FakeStoreAPI
  • Giúp chúng tôi gửi và whatsappcloudapi_wrappernhận tin nhắn WhatsApp

Tiếp theo, chúng ta sẽ tạo ba tệp:

  1. ./app.js
  2. ./.env.js
  3. ./routes/index.js

Trong ./.env.jstệp của chúng tôi, hãy nhập mã dưới đây:

const production = {
    ...process.env,
    NODE_ENV: process.env.NODE_ENV || 'production',
};

const development = {
    ...process.env,
    NODE_ENV: process.env.NODE_ENV || 'development',
    PORT: '9000',
    Meta_WA_accessToken:'EAAKGUD3eZA28BADAJOmO6L19TmZAIEUpdFGHEGHX5sQ3kk4LDQLlnyh607rKSr0x2SAOPJS0kXOUZAhRDIPPGs4vcXQCo2DnfSJMnnIzFW7vaw8EuL7A0HjGZBwE8VwjRnBNam0ARLmfyOCEh1',
    Meta_WA_SenderPhoneNumberId: '113362588047543',
    Meta_WA_wabaId: '102432872486730',
    Meta_WA_VerifyToken: 'YouCanSetYourOwnToken',
};

const fallback = {
    ...process.env,
    NODE_ENV: undefined,
};

module.exports = (environment) => {
    console.log(`Execution environment selected is: "${environment}"`);
    if (environment === 'production') {
        return production;
    } else if (environment === 'development') {
        return development;
    } else {
        return fallback;
    }
};

Trong cùng một ./.env.jstệp:

  1. Thay thế giá trị của Meta_WA_accessTokenbằng mã thông báo truy cập tạm thời cho ứng dụng Meta của bạn
  2. Thay thế giá trị của Meta_WA_SenderPhoneNumberIdbằng ID số điện thoại của bạn
  3. Thay thế giá trị của Meta_WA_wabaIdbằng ID tài khoản doanh nghiệp WhatsApp của bạn
  4. Đặt giá trị của riêng bạn cho Meta_WA_VerifyToken. Nó có thể là một chuỗi hoặc một số; bạn sẽ thấy cách chúng tôi sử dụng nó trong bước webhooks

Đoạn mã trên trước tiên nhập các biến môi trường hiện tại và hủy chúng, sau đó thêm các biến môi trường mới và xuất kết hợp của cả hai dưới dạng một đối tượng.

Trong tệp ./app.jstệp, hãy chèn mã dưới đây:

process.env = require('./.env.js')(process.env.NODE_ENV || 'development');
const port = process.env.PORT || 9000;
const express = require('express');

let indexRoutes = require('./routes/index.js');

const main = async () => {
    const app = express();
    app.use(express.json());
    app.use(express.urlencoded({ extended: false }));
    app.use('/', indexRoutes);
    app.use('*', (req, res) => res.status(404).send('404 Not Found'));
    app.listen(port, () =>
        console.log(`App now running and listening on port ${port}`)
    );
};
main();

Dòng đầu tiên của khối mã ở trên chỉ cần nhập ./.env.jstệp và gán tệp cho nó process.env, đây là một đối tượng có thể truy cập toàn cầu trong Node.js.

Trong tệp ./routes/index.js, hãy chèn mã dưới đây:

'use strict';
const router = require('express').Router();

router.get('/meta_wa_callbackurl', (req, res) => {
    try {
        console.log('GET: Someone is pinging me!');

        let mode = req.query['hub.mode'];
        let token = req.query['hub.verify_token'];
        let challenge = req.query['hub.challenge'];

        if (
            mode &&
            token &&
            mode === 'subscribe' &&
            process.env.Meta_WA_VerifyToken === token
        ) {
            return res.status(200).send(challenge);
        } else {
            return res.sendStatus(403);
        }
    } catch (error) {
        console.error({error})
        return res.sendStatus(500);
    }
});

router.post('/meta_wa_callbackurl', async (req, res) => {
    try {
        console.log('POST: Someone is pinging me!');
        return res.sendStatus(200);
    } catch (error) {
                console.error({error})
        return res.sendStatus(500);
    }
});
module.exports = router;

Tiếp theo, mở thiết bị đầu cuối và chạy:

nodemon app.js

Máy chủ Express sẽ chạy trên cổng 9000.

Tiếp theo, mở một thiết bị đầu cuối khác, riêng biệt và chạy:

ngrok http 9000

Lệnh này hiển thị ứng dụng Express của chúng tôi với internet rộng lớn hơn. Mục tiêu ở đây là thiết lập một webhook mà WhatsApp Cloud có thể ping.

Lưu ý URL mà ngrok chỉ định cho máy chủ Express của bạn. Trong ví dụ của tôi, ngrok đã cấp cho tôi URL này https://7b9b-102-219-204-54.ngrok.io:. Giữ cho cả máy chủ Express và thiết bị đầu cuối ngrok chạy.

Tiếp theo, hãy tiếp tục công việc của chúng ta trong bảng điều khiển Meta Developer. Cuộn đến phần có tiêu đề Định cấu hình Webhooks để nhận tin nhắn và nhấp vào Định cấu hình Webhooks . Liên kết sẽ hiển thị một trang giống như ảnh chụp màn hình bên dưới:

Trang cấu hình webhooks

Nhấp vào nút Chỉnh sửa và một cửa sổ bật lên sẽ hiển thị.

Trong trường URL gọi lại , hãy dán URL mà ngrok đã cấp cho bạn và nối nó với tuyến gọi lại, như trong lệnh ./routes/index.js. URL đầy đủ của tôi, trong trường hợp này, là https://7b9b-102-219-204-54.ngrok.io/meta_wa_callbackurl.

Trong trường Xác minh mã thông báo , hãy nhập giá trị của Meta_WA_VerifyToken khi nó xuất hiện trong ./.env.jstệp của bạn.

Nhập giá trị vào trường mã thông báo xác minh

Sau đó nhấp vào Xác minh và lưu .

Nếu bạn đã định cấu hình điều này tốt, bạn sẽ thấy một console.logthông báo trong thiết bị đầu cuối của máy chủ Express cho biết:

GET: Ai đó đang ping tôi!

Định cấu hình máy chủ Express của chúng tôi

Bây giờ, hãy làm cho máy chủ Express của chúng tôi nhận tin nhắn đăng ký từ Meta.

Trên cùng một màn hình bảng điều khiển Meta Developers, nhấp vào Quản lý và một cửa sổ bật lên sẽ xuất hiện.

Quản lý cửa sổ bật lên thông báo đăng ký máy chủ nhanh

Chọn Tin nhắn và nhấp vào Kiểm tra , trên cùng một hàng.

Bạn sẽ thấy một console.logthông báo trong thiết bị đầu cuối của máy chủ Express có nội dung:

BÀI ĐĂNG: Ai đó đang ping tôi!

Nếu bạn thấy thông báo này, hãy quay lại cùng một cửa sổ bật lên và nhấp vào Đăng ký trong cùng một hàng thông báo. Sau đó, nhấp vào Xong .

Bước 3: Viết logic kinh doanh của chúng tôi

Định cấu hình nguồn dữ liệu thương mại điện tử

Đầu tiên, chúng tôi sẽ thiết lập logic của mình để tìm nạp dữ liệu từ FakeStoreAPI, tạo hóa đơn PDF và tạo địa điểm nhận đơn đặt hàng giả. Chúng tôi sẽ gói logic này thành một lớp JavaScript, sau đó chúng tôi sẽ nhập vào logic của ứng dụng.

Tạo một tệp và đặt tên cho nó ./utils/ecommerce_store.js. Trong tệp này, hãy dán mã sau:

'use strict';
const request = require('request');
const PDFDocument = require('pdfkit');
const fs = require('fs');

module.exports = class EcommerceStore {
    constructor() {}
    async _fetchAssistant(endpoint) {
        return new Promise((resolve, reject) => {
            request.get(
                `https://fakestoreapi.com${endpoint ? endpoint : '/'}`,
                (error, res, body) => {
                    try {
                        if (error) {
                            reject(error);
                        } else {
                            resolve({
                                status: 'success',
                                data: JSON.parse(body),
                            });
                        }
                    } catch (error) {
                        reject(error);
                    }
                }
            );
        });
    }

    async getProductById(productId) {
        return await this._fetchAssistant(`/products/${productId}`);
    }
    async getAllCategories() {
        return await this._fetchAssistant('/products/categories?limit=100');
    }
    async getProductsInCategory(categoryId) {
        return await this._fetchAssistant(
            `/products/category/${categoryId}?limit=10`
        );
    }

    generatePDFInvoice({ order_details, file_path }) {
        const doc = new PDFDocument();
        doc.pipe(fs.createWriteStream(file_path));
        doc.fontSize(25);
        doc.text(order_details, 100, 100);
        doc.end();
        return;
    }

    generateRandomGeoLocation() {
        let storeLocations = [
            {
                latitude: 44.985613,
                longitude: 20.1568773,
                address: 'New Castle',
            },
            {
                latitude: 36.929749,
                longitude: 98.480195,
                address: 'Glacier Hill',
            },
            {
                latitude: 28.91667,
                longitude: 30.85,
                address: 'Buena Vista',
            },
        ];
        return storeLocations[
            Math.floor(Math.random() * storeLocations.length)
        ];
    }
};

Trong đoạn mã trên, chúng ta đã tạo một lớp được gọi là EcommerceStore.

Phương thức đầu tiên _fetchAssistant, nhận một điểm cuối mà nó sử dụng để ping fakestoreapi.com .

Các phương thức sau hoạt động như trình tạo truy vấn cho phương thức đầu tiên:

  1. getProductById nhận ID sản phẩm và sau đó nhận dữ liệu liên quan đến sản phẩm cụ thể đó
  2. getAllCategories tìm nạp tất cả các danh mục có trong fakestoreapi.com
  3. getProductsInCategory nhận một danh mục sản phẩm và sau đó tiến hành tìm nạp tất cả các sản phẩm trong danh mục cụ thể đó

Các trình xây dựng truy vấn này sẽ gọi phương thức đầu tiên.

Tiếp tục, phương thức generatePDFInvoice nhận một đoạn văn bản và một đường dẫn tệp. Sau đó, nó tạo một tài liệu PDF, viết văn bản trên đó và sau đó lưu trữ tài liệu trong đường dẫn tệp được cung cấp.

Phương thức này generateRandomGeoLocation chỉ trả về một vị trí địa lý ngẫu nhiên. Phương pháp này sẽ hữu ích khi chúng tôi gửi địa điểm nhận đơn hàng của shop cho khách hàng muốn lấy hàng của họ.

Định cấu hình phiên khách hàng

Để xử lý hành trình của khách hàng, chúng tôi cần giữ một phiên bao gồm hồ sơ khách hàng và giỏ hàng của họ. Do đó, mỗi khách hàng sẽ có phiên duy nhất của riêng họ.

Trong quá trình sản xuất, chúng tôi có thể sử dụng cơ sở dữ liệu như MySQL, MongoDB hoặc một thứ gì đó khác có khả năng phục hồi, nhưng để giữ cho hướng dẫn của chúng tôi gọn gàng và ngắn gọn, chúng tôi sẽ sử dụng cấu trúc dữ liệu của ES2015Map . Với Map, chúng tôi có thể lưu trữ và truy xuất dữ liệu cụ thể, có thể lặp lại, chẳng hạn như dữ liệu khách hàng duy nhất.

Trong ./routes/index.jstệp của bạn, hãy thêm đoạn mã sau ngay bên trên router.get('/meta_wa_callbackurl', (req, res).

const EcommerceStore = require('./../utils/ecommerce_store.js');
let Store = new EcommerceStore();
const CustomerSession = new Map();

router.get('/meta_wa_callbackurl', (req, res) => {//this line already exists. Add the above lines

Dòng đầu tiên nhập EcommerceStorelớp, trong khi dòng thứ hai khởi tạo nó. Dòng thứ ba tạo phiên của khách hàng mà chúng tôi sẽ sử dụng để lưu trữ hành trình của khách hàng.

Khởi tạo API đám mây WhatsApp của chúng tôi

Nhớ whatsappcloudapi_wrappergói mà chúng tôi đã cài đặt trước đó? Đã đến lúc nhập và khởi tạo nó.

Trong ./routes/index.jstệp, hãy thêm các dòng mã sau vào bên dưới khai báo bộ định tuyến Express:

const router = require('express').Router(); // This line already exists. Below it add  the following lines:

const WhatsappCloudAPI = require('whatsappcloudapi_wrapper');
const Whatsapp = new WhatsappCloudAPI({
    accessToken: process.env.Meta_WA_accessToken,
    senderPhoneNumberId: process.env.Meta_WA_SenderPhoneNumberId,
    WABA_ID: process.env.Meta_WA_wabaId,
});

Các giá trị sau là các biến môi trường mà chúng tôi đã xác định trong ./.env.jstệp của mình:

  • process.env.Meta_WA_accessToken
  • process.env.Meta_WA_SenderPhoneNumberId
  • process.env.Meta_WA_wabaId

Chúng tôi khởi tạo lớp WhatsAppCloudAPI với ba giá trị ở trên và đặt tên cho phiên bản của chúng tôi Whatsapp.

Tiếp theo, hãy phân tích cú pháp tất cả dữ liệu được đưa vào /meta_wa_callbackurlwebhook POST. Bằng cách phân tích cú pháp nội dung của các yêu cầu, chúng tôi sẽ có thể trích xuất tin nhắn và các chi tiết khác, như tên của người gửi, số điện thoại của người gửi, v.v.

Xin lưu ý : Tất cả các chỉnh sửa mã mà chúng tôi thực hiện từ thời điểm này sẽ hoàn toàn được thực hiện trong ./routes/index.jstệp.

Thêm các dòng mã sau vào bên dưới dấu ngoặc mở của try{câu lệnh:

try { // This line already exists. Add the below lines

        let data = Whatsapp.parseMessage(req.body);

        if (data?.isMessage) {
            let incomingMessage = data.message;
            let recipientPhone = incomingMessage.from.phone; // extract the phone number of sender
            let recipientName = incomingMessage.from.name;
            let typeOfMsg = incomingMessage.type; // extract the type of message (some are text, others are images, others are responses to buttons etc...)
            let message_id = incomingMessage.message_id; // extract the message id
        }

Bây giờ, khi khách hàng gửi tin nhắn cho chúng tôi, webhook của chúng tôi sẽ nhận được tin nhắn đó. Tin nhắn được chứa trong phần nội dung yêu cầu của webhook. Để trích xuất thông tin hữu ích ra khỏi phần nội dung của yêu cầu, chúng tôi cần chuyển phần nội dung đó vào parseMessagephương thức của phiên bản WhatsApp.

Sau đó, sử dụng một ifcâu lệnh, chúng tôi kiểm tra xem kết quả của phương pháp có chứa một tin nhắn WhatsApp hợp lệ hay không.

Bên trong ifcâu lệnh, chúng tôi xác định incomingMessage, có chứa thông báo. Chúng tôi cũng xác định các biến khác:

  • recipientPhonelà số của khách hàng đã gửi tin nhắn cho chúng tôi. Chúng tôi sẽ gửi cho họ một tin nhắn trả lời, do đó có tiền tố "người nhận"
  • recipientNamelà tên của khách hàng đã gửi tin nhắn cho chúng tôi. Đây là tên họ đã đặt cho mình trong hồ sơ WhatsApp của họ
  • typeOfMsglà loại tin nhắn mà một khách hàng đã gửi cho chúng tôi. Như chúng ta sẽ thấy ở phần sau, một số tin nhắn là văn bản đơn giản, trong khi những tin nhắn khác là trả lời cho các nút (đừng lo lắng, điều này sẽ sớm có ý nghĩa!)
  • message_idlà một chuỗi ký tự xác định duy nhất một tin nhắn mà chúng tôi đã nhận được. Điều này hữu ích khi chúng tôi muốn thực hiện các tác vụ cụ thể cho thư đó, chẳng hạn như đánh dấu thư là đã đọc

Cho đến thời điểm này, tất cả đều có vẻ ổn, nhưng chúng tôi sẽ xác nhận ngay sau đây.

Hiểu và đáp ứng ý định của khách hàng

Vì hướng dẫn của chúng tôi sẽ không đi sâu vào bất kỳ hình thức xử lý AI hoặc ngôn ngữ tự nhiên (NLP) nào, chúng tôi sẽ xác định luồng trò chuyện của mình bằng if…elselogic đơn giản.

Logic hội thoại bắt đầu khi khách hàng gửi tin nhắn văn bản. Chúng tôi sẽ không xem xét bản thân thông báo, vì vậy chúng tôi sẽ không biết họ định làm gì, nhưng chúng tôi có thể cho khách hàng biết bot của chúng tôi có thể làm gì.

Hãy cung cấp cho khách hàng một ngữ cảnh đơn giản để họ có thể trả lời với một mục đích cụ thể.

Chúng tôi sẽ cung cấp cho khách hàng hai nút:

  1. Một cho chúng tôi biết họ muốn nói chuyện với một con người thực tế, không phải một chatbot
  2. Một cái khác để duyệt sản phẩm

Để thực hiện việc này, hãy chèn đoạn mã sau vào bên dưới message_id:

if (typeOfMsg === 'text_message') {
    await Whatsapp.sendSimpleButtons({
        message: `Hey ${recipientName}, \nYou are speaking to a chatbot.\nWhat do you want to do next?`,
        recipientPhone: recipientPhone, 
        listOfButtons: [
            {
                title: 'View some products',
                id: 'see_categories',
            },
            {
                title: 'Speak to a human',
                id: 'speak_to_human',
            },
        ],
    });
}

Tuyên bố trên ifchỉ cho phép chúng tôi xử lý tin nhắn văn bản.

Phương sendSimpleButtonspháp này cho phép chúng tôi gửi các nút tới khách hàng. Ghi chú về các thuộc tính titleid. Đó là những gì khách titlehàng sẽ thấy và idlà những gì chúng tôi sẽ sử dụng để biết khách hàng đã nhấp vào nút nào.

Hãy kiểm tra xem chúng tôi đã làm điều này đúng. Mở ứng dụng WhatsApp của bạn và gửi tin nhắn văn bản đến tài khoản doanh nghiệp WhatsApp.

Gửi tin nhắn văn bản đến tài khoản doanh nghiệp WhatsApp

Nếu bạn nhận được phản hồi như ảnh chụp màn hình ở trên, xin chúc mừng! Bạn vừa gửi tin nhắn đầu tiên của mình qua API đám mây WhatsApp.

Vì khách hàng có thể nhấp vào một trong hai nút, chúng ta hãy quan tâm đến nút Nói với một người .

Bên ngoài ifcâu lệnh text_messagelogic, hãy chèn đoạn mã sau:

if (typeOfMsg === 'simple_button_message') {
    let button_id = incomingMessage.button_reply.id;

    if (button_id === 'speak_to_human') {
        await Whatsapp.sendText({
            recipientPhone: recipientPhone,
            message: `Arguably, chatbots are faster than humans.\nCall my human with the below details:`,
        });

        await Whatsapp.sendContact({
            recipientPhone: recipientPhone,
            contact_profile: {
                addresses: [
                    {
                        city: 'Nairobi',
                        country: 'Kenya',
                    },
                ],
                name: {
                    first_name: 'Daggie',
                    last_name: 'Blanqx',
                },
                org: {
                    company: 'Mom-N-Pop Shop',
                },
                phones: [
                    {
                        phone: '+1 (555) 025-3483',
                    },
                                        {
                        phone: '+254712345678',
                    },
                ],
            },
        });
    }
};

Đoạn mã trên thực hiện hai hành động:

  1. Gửi tin nhắn văn bản để cho người dùng biết rằng họ sẽ nhận được thẻ liên hệ, sử dụng sendTextphương pháp này
  2. Gửi thẻ liên hệ bằng sendContactphương thức này

Mã này cũng phát hiện ý định của người dùng bằng cách sử dụng ID của nút mà người dùng đã nhấp vào (trong trường hợp của chúng tôi, ID là incomingMessage.button_reply.id), và sau đó nó phản hồi với hai tùy chọn hành động.

Bây giờ, quay lại WhatsApp và nhấp vào Nói chuyện với con người . Nếu bạn làm đúng, bạn sẽ thấy một câu trả lời như sau:

Gửi "Nói chuyện với con người" và nhận tệp đính kèm liên hệ

Khi bạn nhấp vào thẻ liên hệ bạn nhận được, bạn sẽ thấy như sau:

Thẻ liên hệ hiển thị đầy đủ tên, doanh nghiệp và hai số điện thoại

Tiếp theo, chúng ta hãy làm việc trên nút Xem một số sản phẩm .

Bên trong simple_button_message ifcâu lệnh, nhưng ngay bên dưới và bên ngoài speak_to_human ifcâu lệnh, hãy thêm đoạn mã sau:

if (button_id === 'see_categories') {
    let categories = await Store.getAllCategories(); 
    await Whatsapp.sendSimpleButtons({
        message: `We have several categories.\nChoose one of them.`,
        recipientPhone: recipientPhone, 
        listOfButtons: categories.data
            .map((category) => ({
                title: category,
                id: `category_${category}`,
            }))
            .slice(0, 3)
    });
}

Đây là những gì đoạn mã trên thực hiện:

  1. Tuyên bố đảm bảo rằng người ifdùng đã nhấp vào nút Xem một số sản phẩm
  2. Tìm nạp danh mục sản phẩm từ FakeStoreAPIphương getAllCategoriesthức
  3. Giới hạn số lượng nút là ba bằng cách sử dụng phương pháp mảng - slice(0,3)- vì WhatsApp chỉ cho phép chúng tôi gửi ba nút đơn giản
  4. Sau đó, nó lặp lại từng danh mục, tạo một nút có một title và một ID duy nhất được bắt đầu bằngcategory_
  5. Với sendSimpleButtonsphương pháp, chúng tôi gửi các nút này cho khách hàng

Quay lại ứng dụng WhatsApp của bạn một lần nữa và nhấp vào Xem các sản phẩm khác . Nếu bạn đã làm đúng các bước trên, bạn sẽ thấy câu trả lời giống như ảnh chụp màn hình bên dưới:

Gửi "xem một số sản phẩm" trong trò chuyện WhatsApp

Tìm nạp sản phẩm theo danh mục

Bây giờ, chúng ta hãy tạo logic để có được sản phẩm trong danh mục mà khách hàng đã chọn.

Vẫn bên trong simple_button_message ifcâu lệnh, nhưng bên dưới và bên ngoài see_categories ifcâu lệnh, hãy thêm mã sau:

if (button_id.startsWith('category_')) {
    let selectedCategory = button_id.split('category_')[1];
    let listOfProducts = await Store.getProductsInCategory(selectedCategory);

    let listOfSections = [
        {
            title: ` Top 3: ${selectedCategory}`.substring(0,24),
            rows: listOfProducts.data
                .map((product) => {
                    let id = `product_${product.id}`.substring(0,256);
                    let title = product.title.substring(0,21);
                    let description = `${product.price}\n${product.description}`.substring(0,68);
                   
                    return {
                        id,
                        title: `${title}...`,
                        description: `$${description}...`
                    };
                }).slice(0, 10)
        },
    ];

    await Whatsapp.sendRadioButtons({
        recipientPhone: recipientPhone,
        headerText: `#BlackFriday Offers: ${selectedCategory}`,
        bodyText: `Our Santa  has lined up some great products for you based on your previous shopping history.\n\nPlease select one of the products below:`,
        footerText: 'Powered by: BMI LLC',
        listOfSections,
    });
}

ifTuyên bố trên xác nhận rằng nút mà khách hàng nhấp vào thực sự là nút có chứa một danh mục .

Điều đầu tiên chúng tôi làm ở đây là trích xuất danh mục cụ thể từ ID của nút. Sau đó, chúng tôi truy vấn FakeStoreAPI của chúng tôi để tìm các sản phẩm thuộc danh mục cụ thể đó.

Sau khi truy vấn, chúng tôi nhận được danh sách các sản phẩm bên trong một mảng , listOfProducts.data. Bây giờ chúng tôi lặp lại mảng này và đối với mỗi sản phẩm trong đó, chúng tôi trích xuất giá, tiêu đề, mô tả và ID của nó.

Chúng tôi thêm product_vào id, điều này sẽ giúp chúng tôi chọn lựa của khách hàng trong bước tiếp theo. Đảm bảo bạn cắt bớt độ dài của ID, tiêu đề và mô tả theo các hạn chế về nút radio (hoặc danh sách) của WhatsApp Cloud API .

Sau đó, chúng tôi trả về ba giá trị: ID, tiêu đề và mô tả. Vì WhatsApp chỉ cho phép chúng tôi tối đa 10 hàng, chúng tôi sẽ giới hạn số lượng sản phẩm là 10 bằng cách sử dụng phương pháp mảng .slice(0,10).

Sau đó, chúng tôi gọi sendRadioButtonsphương thức để gửi sản phẩm cho khách hàng. Ghi lại các thuộc tính , và . headerTextbodyTextfooterTextlistOfSections

Quay lại ứng dụng WhatsApp và nhấp vào bất kỳ danh mục sản phẩm nào. Nếu bạn đã làm theo đúng hướng dẫn, bạn sẽ thấy câu trả lời giống như ảnh chụp màn hình bên dưới:

Chọn danh mục điện tử và nhận phản hồi

Khi bạn nhấp vào Chọn một sản phẩm , bạn sẽ thấy màn hình sau:

Chọn một màn hình bật lên của sản phẩmTại thời điểm này, khách hàng có thể chọn một sản phẩm mà họ cảm thấy thú vị, nhưng liệu chúng ta có thể biết họ đã chọn những gì? Vẫn chưa, vì vậy hãy để chúng tôi làm việc trên phần này.

Bên ngoài simple_button_message ifcâu lệnh, hãy để chúng tôi thêm một ifcâu lệnh khác:

if (typeOfMsg === 'radio_button_message') {
    let selectionId = incomingMessage.list_reply.id; // the customer clicked and submitted a radio button
    
}

Bên trong ifcâu lệnh trên và ngay bên dưới câu lệnh selectionId, hãy thêm đoạn mã sau:

if (selectionId.startsWith('product_')) {
    let product_id = selectionId.split('_')[1];
    let product = await Store.getProductById(product_id);
    const { price, title, description, category, image: imageUrl, rating } = product.data;

    let emojiRating = (rvalue) => {
        rvalue = Math.floor(rvalue || 0); // generate as many star emojis as whole number ratings
        let output = [];
        for (var i = 0; i < rvalue; i++) output.push('');
        return output.length ? output.join('') : 'N/A';
    };

    let text = `_Title_: *${title.trim()}*\n\n\n`;
    text += `_Description_: ${description.trim()}\n\n\n`;
    text += `_Price_: $${price}\n`;
    text += `_Category_: ${category}\n`;
    text += `${rating?.count || 0} shoppers liked this product.\n`;
    text += `_Rated_: ${emojiRating(rating?.rate)}\n`;

    await Whatsapp.sendImage({
        recipientPhone,
        url: imageUrl,
        caption: text,
    });

    await Whatsapp.sendSimpleButtons({
        message: `Here is the product, what do you want to do next?`,
        recipientPhone: recipientPhone, 
        listOfButtons: [
            {
                title: 'Add to cart',
                id: `add_to_cart_${product_id}`,
            },
            {
                title: 'Speak to a human',
                id: 'speak_to_human',
            },
            {
                title: 'See more products',
                id: 'see_categories',
            },
        ],
    });
}

Đoạn mã trên thực hiện những việc sau:

  1. Trích xuất ID sản phẩm từ nút radio mà khách hàng đã nhấp vào
  2. Truy vấn FakeStoreAPI với ID sản phẩm đó
  3. Khi nhận và trích xuất dữ liệu của sản phẩm, nó sẽ định dạng văn bản. WhatsApp sử dụng dấu gạch dưới để hiển thị văn bản in nghiêng, trong khi dấu hoa thị hiển thị văn bản in đậm
  4. Hiển thị biểu tượng cảm xúc ngôi sao bằng cách sử dụng emojiRatingchức năng. Nếu xếp hạng là 3,8, nó sẽ hiển thị biểu tượng cảm xúc ba sao
  5. Đính kèm hình ảnh của sản phẩm vào văn bản được hiển thị và gửi nó bằng sendImagephương thức

Sau đó, chúng tôi gửi cho khách hàng danh sách ba nút bằng cách sử dụng sendSimpleButtons. Một cung cấp cho khách hàng cơ hội để thêm sản phẩm vào giỏ hàng của họ. Hãy lưu ý đến ID của nút có tiền tố add_to_cart_.

Bây giờ, quay lại ứng dụng WhatsApp của bạn và chọn một sản phẩm. Nếu bạn đã làm theo đúng hướng dẫn, bạn sẽ thấy câu trả lời giống như ảnh chụp màn hình sau:

Chatbot gửi cho khách hàng ba nút có thể lựa chọn

Phiên xây dựng để lưu trữ giỏ hàng của khách hàng

Để theo dõi các sản phẩm mà khách hàng thêm vào giỏ hàng của họ, chúng tôi cần có một nơi để lưu trữ các mặt hàng trong giỏ hàng. Đây là nơi CustomerSessionphát huy tác dụng. Hãy thêm một số logic vào nó.

Bên ngoài radio_button_message ifcâu lệnh và ngay bên dưới phần message_idkhai báo, hãy thêm đoạn mã sau:

let message_id = incomingMessage.message_id; // This line already exists. Add the below lines...

// Start of cart logic
if (!CustomerSession.get(recipientPhone)) {
    CustomerSession.set(recipientPhone, {
        cart: [],
    });
}

let addToCart = async ({ product_id, recipientPhone }) => {
    let product = await Store.getProductById(product_id);
    if (product.status === 'success') {
        CustomerSession.get(recipientPhone).cart.push(product.data);
    }
};

let listOfItemsInCart = ({ recipientPhone }) => {
    let total = 0;
    let products = CustomerSession.get(recipientPhone).cart;
    total = products.reduce(
        (acc, product) => acc + product.price,
        total
    );
    let count = products.length;
    return { total, products, count };
};

let clearCart = ({ recipientPhone }) => {
    CustomerSession.get(recipientPhone).cart = [];
};
// End of cart logic

if (typeOfMsg === 'text_message') { ... // This line already exists. Add the above lines...

Đoạn mã trên kiểm tra xem phiên của khách hàng đã được tạo hay chưa. Nếu nó chưa được tạo, nó sẽ tạo một phiên mới được nhận dạng duy nhất bởi số điện thoại của khách hàng. Sau đó, chúng tôi khởi tạo một thuộc tính được gọi cart, bắt đầu dưới dạng một mảng trống.

Hàm addToCartnhận a product_idvà số lượng khách hàng cụ thể. Sau đó, nó ping FakeStoreAPI để biết dữ liệu của sản phẩm cụ thể và đẩy sản phẩm vào cartmảng.

Sau đó, listOfItemsInCart hàm này lấy số điện thoại của khách hàng và truy xuất số điện thoại được liên kết cart, được sử dụng để tính số lượng sản phẩm trong giỏ hàng và tổng giá của chúng. Cuối cùng, nó trả về các mặt hàng trong giỏ hàng và tổng giá của chúng.

Chức clearCartnăng lấy số điện thoại của khách hàng và chuyển vào giỏ hàng của khách hàng đó.

Với logic giỏ hàng được thực hiện, hãy xây dựng nút Thêm vào giỏ hàng . Bên trong simple_button_message ifcâu lệnh và bên dưới phần button_idkhai báo, hãy thêm đoạn mã sau:

if (button_id.startsWith('add_to_cart_')) {
    let product_id = button_id.split('add_to_cart_')[1];
    await addToCart({ recipientPhone, product_id });
    let numberOfItemsInCart = listOfItemsInCart({ recipientPhone }).count;

    await Whatsapp.sendSimpleButtons({
        message: `Your cart has been updated.\nNumber of items in cart: ${numberOfItemsInCart}.\n\nWhat do you want to do next?`,
        recipientPhone: recipientPhone, 
        listOfButtons: [
            {
                title: 'Checkout ',
                id: `checkout`,
            },
            {
                title: 'See more products',
                id: 'see_categories',
            },
        ],
    });
}

Đoạn mã trên trích xuất ID sản phẩm từ nút khách hàng nhấp vào, sau đó gọi addToCartchức năng lưu sản phẩm vào giỏ hàng của phiên khách hàng. Sau đó, nó trích xuất số lượng mặt hàng trong giỏ hàng của phiên của khách hàng và cho khách hàng biết họ có bao nhiêu sản phẩm. Nó cũng gửi hai nút, một trong số đó cho phép người dùng kiểm tra.

Ghi lại ID nút và quay lại ứng dụng WhatsApp của bạn. Nhấp vào Thêm vào giỏ hàng . Nếu bạn làm theo đúng hướng dẫn, bạn sẽ thấy câu trả lời giống như ảnh chụp màn hình bên dưới:

Thêm vào giỏ hàng

Bây giờ khách hàng của chúng tôi có thể thêm các mặt hàng vào giỏ hàng, chúng tôi có thể viết logic để thanh toán.

Viết logic thanh toán

Bên trong simple_button_message ifcâu lệnh nhưng bên ngoài add_to_cart_ ifcâu lệnh, hãy thêm đoạn mã sau:

if (button_id === 'checkout') {
  let finalBill = listOfItemsInCart({ recipientPhone });
  let invoiceText = `List of items in your cart:\n`;

  finalBill.products.forEach((item, index) => {
      let serial = index + 1;
      invoiceText += `\n#${serial}: ${item.title} @ $${item.price}`;
  });

  invoiceText += `\n\nTotal: $${finalBill.total}`;

  Store.generatePDFInvoice({
      order_details: invoiceText,
      file_path: `./invoice_${recipientName}.pdf`,
  });

  await Whatsapp.sendText({
      message: invoiceText,
      recipientPhone: recipientPhone,
  });

  await Whatsapp.sendSimpleButtons({
      recipientPhone: recipientPhone,
      message: `Thank you for shopping with us, ${recipientName}.\n\nYour order has been received & will be processed shortly.`,
      message_id,
      listOfButtons: [
          {
              title: 'See more products',
              id: 'see_categories',
          },
          {
              title: 'Print my invoice',
              id: 'print_invoice',
          },
      ],
  });

  clearCart({ recipientPhone });
}

Đoạn mã trên thực hiện những việc sau:

  1. Nhận tất cả các mặt hàng trong giỏ hàng và đặt chúng vào bên trongfinalBill
  2. Khởi tạo một biến invoiceText, biến này sẽ chứa văn bản mà chúng tôi sẽ gửi cho khách hàng cũng như văn bản sẽ được soạn thảo thành phiên bản PDF của hóa đơn
    1. Vòng forEachlặp chỉ đơn giản là nối titlepricecủa từng sản phẩm với hóa đơn
  3. Phương generatePDFInvoicethức (giống phương thức mà chúng tôi đã xác định trong EcommerceStorelớp của mình) lấy chi tiết của đơn đặt hàng, soạn thảo tài liệu PDF và lưu nó vào đường dẫn tệp trong thư mục / thư mục cục bộ mà chúng tôi đã cung cấp
  4. Phương sendTextthức gửi một tin nhắn văn bản đơn giản chứa thông tin chi tiết về đơn đặt hàng cho khách hàng
  5. sendSimpleButtonsgửi một số nút cho khách hàng. Hãy lưu ý đến nút In hóa đơn của tôi và ID của nó
  6. Cuối cùng, clearCartphương pháp làm trống giỏ hàng

Bây giờ, hãy quay lại ứng dụng WhatsApp của bạn và nhấp vào Thanh toán . Nếu bạn làm theo đúng hướng dẫn, bạn sẽ thấy một câu trả lời giống như ảnh chụp màn hình sau:

Nhấp vào nút thanh toán

Tại thời điểm này, khách hàng sẽ nhận được hóa đơn PDF có thể in được. Vì lý do này, hãy để chúng tôi làm việc trên một số logic liên quan đến nút In hóa đơn của tôi .

Viết logic hóa đơn có thể in của chúng tôi

Bên trong simple_button_message ifcâu lệnh nhưng bên ngoài checkout ifcâu lệnh, hãy thêm đoạn mã sau:

if (button_id === 'print_invoice') {
  // Send the PDF invoice
  await Whatsapp.sendDocument({
      recipientPhone: recipientPhone,
      caption:`Mom-N-Pop Shop invoice #${recipientName}`
      file_path: `./invoice_${recipientName}.pdf`,
  });

  // Send the location of our pickup station to the customer, so they can come and pick up their order
  let warehouse = Store.generateRandomGeoLocation();

  await Whatsapp.sendText({
      recipientPhone: recipientPhone,
      message: `Your order has been fulfilled. Come and pick it up, as you pay, here:`,
  });

  await Whatsapp.sendLocation({
      recipientPhone,
      latitude: warehouse.latitude,
      longitude: warehouse.longitude,
      address: warehouse.address,
      name: 'Mom-N-Pop Shop',
  });
}

Đoạn mã trên lấy tài liệu PDF được tạo ở bước trước từ hệ thống tệp cục bộ và gửi cho khách hàng bằng sendDocumentphương pháp này.

Khi một khách hàng đặt mua một sản phẩm trực tuyến, họ cũng cần biết họ sẽ nhận được sản phẩm vật chất như thế nào. Vì lý do này, chúng tôi đã tạo một số tọa độ ngẫu nhiên bằng cách sử dụng generateRandomGeoLocationphương thức của EcommerceStorelớp và gửi các tọa độ này cho khách hàng bằng sendLocationphương pháp này để cho họ biết nơi họ có thể lấy sản phẩm của mình.

Bây giờ, hãy mở ứng dụng WhatsApp của bạn và nhấp vào In hóa đơn của tôi .

Nếu bạn đã làm theo đúng hướng dẫn ở trên, bạn sẽ thấy câu trả lời giống với ảnh chụp màn hình bên dưới:

Nhắn tin "in hóa đơn của tôi" và nhận tệp PDF và hướng dẫn lấy sản phẩm.

Hiển thị biên nhận đã đọc cho khách hàng

Cuối cùng, bạn có thể nhận thấy rằng các dấu kiểm bên dưới thư có màu xám thay vì màu xanh lam. Điều này cho thấy rằng các tin nhắn chúng tôi đã gửi không trả lại các xác nhận đã đọc mặc dù thực tế là bot của chúng tôi đang đọc chúng.

Những con bọ màu xám có thể gây khó chịu cho khách hàng và vì lý do này, chúng tôi cần làm việc để hiển thị những con bọ màu xanh lam.

Bên ngoài simple_button_message ifcâu lệnh và trước dấu ngoặc nhọn đóng của data?.isMessage ifcâu lệnh, hãy thêm đoạn mã sau:

await Whatsapp.markMessageAsRead({ message_id });

Một dòng chữ đơn giản này đánh dấu một tin nhắn được đọc ngay sau khi chúng tôi trả lời nó.

Bây giờ, hãy mở ứng dụng WhatsApp của bạn và gửi một tin nhắn văn bản ngẫu nhiên. Bạn có thấy những gì tôi đang thấy không?

Tin nhắn "hey" và chatbot trả lời bằng tin nhắn mặc định

Nếu các cuộc trò chuyện trước đó của bạn đã được cập nhật bằng dấu tích màu xanh, thì xin chúc mừng! Bạn đã xem đến phần cuối của hướng dẫn này và học được một số điều trong suốt quá trình.

Suy nghĩ cuối cùng

Với tổng số 2 tỷ người dùng hoạt động hàng tháng, việc bỏ qua WhatsApp như một chiến lược thương mại điện tử là một cách chắc chắn để tụt hậu so với đối thủ cạnh tranh của doanh nghiệp bạn và vì hầu hết khách hàng của bạn đã sử dụng WhatsApp trong các hoạt động hàng ngày của họ, tại sao không nên ' doanh nghiệp của bạn có gặp họ ở đó không?

Tôi hy vọng hướng dẫn này sẽ hữu ích trong việc làm sáng tỏ API đám mây WhatsApp và tôi hy vọng bạn đã có một chút thú vị trong suốt quá trình này. Hãy cho tôi biết những chủ đề khác mà bạn có thể thấy thú vị và đừng quên chia sẻ bài viết này với giới công nghệ của bạn.

 Nguồn: https://blog.logrocket.com/build-ecommerce-app-whatsapp-cloud-api-node-js/

#whatsapp #ecommerce #cloud #api #nodejs 

What is GEEK

Buddha Community

Xây Dựng ứng Dụng Thương Mại điện Tử Tự động Với WhatsApp Cloud API
Hoang  Kim

Hoang Kim

1658842095

Xây Dựng ứng Dụng Thương Mại điện Tử Tự động Với WhatsApp Cloud API

Vào tháng 5 năm 2022, Meta (công ty trước đây được gọi là Facebook, sở hữu WhatsApp) thông báo rằng họ sẽ mở rộng API kinh doanh WhatsApp cho công chúng. Bài viết này dự định chào mừng bạn đến với thế giới cơ hội của Meta, nơi chatbot WhatsApp có thể giúp bạn tạo khách hàng tiềm năng, nhận đơn đặt hàng, lên lịch cuộc hẹn, chạy khảo sát, lấy ý kiến ​​phản hồi của khách hàng, cung cấp hỗ trợ khách hàng có thể mở rộng, gửi hóa đơn và biên nhận, v.v.

Hướng dẫn này sẽ đi sâu vào các phần kỹ thuật của việc xây dựng một chatbot WhatsApp từ đầu.

Đến cuối hướng dẫn này, bạn sẽ tạo được chatbot WhatsApp của riêng mình.

Hướng dẫn của chúng tôi tập trung vào một cửa hàng thương mại điện tử đơn giản dành cho mẹ và người mua bán các mặt hàng gia dụng và thời trang nhanh. Doanh nghiệp sẽ có một chatbot WhatsApp, nơi khách hàng có thể duyệt và mua từ cửa hàng thương mại điện tử.

Mọi cửa hàng thương mại điện tử đều cần sản phẩm (giá cả, tên, mô tả, v.v.) và đối với hướng dẫn này, chúng tôi sẽ sử dụng các sản phẩm giả từ FakeStoreAPI .

Điều kiện tiên quyết

Trước khi chúng tôi tiếp tục, bài viết này giả định rằng:

  • Bạn có tài khoản nhà phát triển Meta hợp lệ. Nếu bạn không, vui lòng xem https://developers.facebook.com/
  • Bạn am hiểu về JavaScript và Node.js
  • Bạn đã cài đặt ngrok

Bước 1: Định cấu hình ứng dụng của chúng tôi trên bảng điều khiển Meta Developer

Bước đầu tiên để sử dụng bất kỳ API nào của Meta là tạo một ứng dụng trên Meta dashboard, điều này hoàn toàn miễn phí.

  • Trong khi đăng nhập vào tài khoản nhà phát triển Meta của bạn, hãy điều hướng đến https://developers.facebook.com/apps
  • Nhấp vào Tạo ứng dụng
  • Trong màn hình tiếp theo, hãy chọn loại ứng dụng Doanh nghiệp

Chọn loại ứng dụng kinh doanh

  • Tiếp theo, điền tên ứng dụng và địa chỉ email của bạn, sau đó chọn trang / doanh nghiệp bạn muốn liên kết với ứng dụng này

Đặt tên ứng dụng và chọn trang được liên kết với nó

  • Sau khi gửi biểu mẫu, bạn sẽ được dẫn đến một màn hình như sau:

Chọn thiết lập WhatsApp

Trên màn hình này, chọn WhatsApp và nhấp vào nút Thiết lập của nó .

Sau đó, bạn sẽ được dẫn đến một màn hình mới, như hình dưới đây.

Trang bắt đầu

Trên màn hình này, hãy lưu ý:

  • ID ứng dụng , là ID được liên kết với ứng dụng Meta của chúng tôi. Của tôi là1184643492312754
  • thông báo truy cập tạm thời , sẽ hết hạn sau 24 giờ. Của tôi bắt đầu bằng EAAQ1bU6LdrIBA
  • Số điện thoại Kiểm tra mà chúng tôi sẽ sử dụng để gửi tin nhắn cho khách hàng. Của tôi là+1 555 025 3483
    • ID số điện thoại . Của tôi là113362588047543
    • ID tài khoản doanh nghiệp WhatsApp . Của tôi là102432872486730

Xin lưu ý rằng mã thông báo truy cập tạm thời sẽ hết hạn sau 24 giờ, tại thời điểm đó chúng tôi cần phải gia hạn mã này. Khi chuyển ứng dụng của mình sang chế độ trực tiếp, bạn có thể đăng ký mã thông báo truy cập vĩnh viễn mà chúng tôi không cần thực hiện vì ứng dụng của chúng tôi đang ở chế độ phát triển.

ID số điện thoại và ID tài khoản doanh nghiệp WhatsApp được gắn với số điện thoại thử nghiệm.

Tiếp theo, hãy thêm một số điện thoại để sử dụng để nhận tin nhắn.

Trong chế độ phát triển, Meta giới hạn chúng tôi ở năm số người nhận vì lý do để ngăn chặn thư rác / lạm dụng. Ở chế độ trực tiếp / sản xuất, số đại diện cho số điện thoại của khách hàng của chúng tôi.

Nhấp vào Chọn số điện thoại người nhận và thêm số WhatsApp của riêng bạn, như được hiển thị trong ảnh chụp màn hình bên dưới:

Thêm hộp thoại số điện thoại người nhận

Sau khi thêm số người nhận, bạn sẽ thấy một màn hình giống như bên dưới. Nếu đây là lần đầu tiên bạn thêm số điện thoại của mình vào các nền tảng Meta - chẳng hạn như Trang Facebook, bộ Meta Business hoặc bảng điều khiển dành cho nhà phát triển Meta - bạn sẽ nhận được thông báo OTP từ Facebook Business nhắc bạn xác minh rằng bạn thực sự sở hữu số người nhận .

Gửi tin nhắn bằng API

Kiểm tra thiết lập của chúng tôi

Hãy kiểm tra xem mọi thứ cho đến bước này có hoạt động tốt không. Chúng tôi sẽ thực hiện việc này bằng cách nhấp vào nút Gửi tin nhắn .

Nếu mọi thứ đều ổn, bạn sẽ thấy một tin nhắn trong hộp thư đến WhatsApp từ số kiểm tra của mình.

Tin nhắn Hello World từ Facebook trong hộp thư đến WhatsApp

Cho đến thời điểm này, chúng tôi đang làm tốt! Hãy tạm dừng và mở trình chỉnh sửa mã của bạn. Đừng đóng tab trình duyệt của bạn vì chúng tôi sẽ quay lại trang tổng quan Nhà phát triển Meta sau vài phút.

Bước 2: Thiết lập webhook để nhận tin nhắn

Bây giờ thiết lập của chúng ta có thể gửi tin nhắn thành công, hãy thiết lập cách nhận tin nhắn. Đã đến lúc chúng ta phải làm bẩn tay và đắm mình trong việc viết mã. Tất cả mã chúng tôi sẽ viết cho hướng dẫn này đều nằm trong kho lưu trữ GitHub này .

Tạo một thư mục mới để chứa dự án của chúng tôi. Mở thư mục này trong một thiết bị đầu cuối và chạy tập lệnh dưới đây:

npm init ---yes

Tiếp theo, chúng tôi cài đặt một số gói:

npm install express pdfkit request whatsappcloudapi_wrapper
npm install nodemon --dev

Dưới đây là giải thích ngắn gọn về từng loại:

  • Gói expressnày rất quan trọng để thiết lập máy chủ của chúng tôi. Máy chủ sẽ chứa một tuyến đường sẽ hoạt động như một webhook của chúng tôi
  • Gói pdfkitnày sẽ được sử dụng để tạo hóa đơn cho khách hàng của chúng tôi khi họ thanh toán
  • Gói request này sẽ giúp chúng tôi chạy các yêu cầu tìm nạp tới FakeStoreAPI
  • Giúp chúng tôi gửi và whatsappcloudapi_wrappernhận tin nhắn WhatsApp

Tiếp theo, chúng ta sẽ tạo ba tệp:

  1. ./app.js
  2. ./.env.js
  3. ./routes/index.js

Trong ./.env.jstệp của chúng tôi, hãy nhập mã dưới đây:

const production = {
    ...process.env,
    NODE_ENV: process.env.NODE_ENV || 'production',
};

const development = {
    ...process.env,
    NODE_ENV: process.env.NODE_ENV || 'development',
    PORT: '9000',
    Meta_WA_accessToken:'EAAKGUD3eZA28BADAJOmO6L19TmZAIEUpdFGHEGHX5sQ3kk4LDQLlnyh607rKSr0x2SAOPJS0kXOUZAhRDIPPGs4vcXQCo2DnfSJMnnIzFW7vaw8EuL7A0HjGZBwE8VwjRnBNam0ARLmfyOCEh1',
    Meta_WA_SenderPhoneNumberId: '113362588047543',
    Meta_WA_wabaId: '102432872486730',
    Meta_WA_VerifyToken: 'YouCanSetYourOwnToken',
};

const fallback = {
    ...process.env,
    NODE_ENV: undefined,
};

module.exports = (environment) => {
    console.log(`Execution environment selected is: "${environment}"`);
    if (environment === 'production') {
        return production;
    } else if (environment === 'development') {
        return development;
    } else {
        return fallback;
    }
};

Trong cùng một ./.env.jstệp:

  1. Thay thế giá trị của Meta_WA_accessTokenbằng mã thông báo truy cập tạm thời cho ứng dụng Meta của bạn
  2. Thay thế giá trị của Meta_WA_SenderPhoneNumberIdbằng ID số điện thoại của bạn
  3. Thay thế giá trị của Meta_WA_wabaIdbằng ID tài khoản doanh nghiệp WhatsApp của bạn
  4. Đặt giá trị của riêng bạn cho Meta_WA_VerifyToken. Nó có thể là một chuỗi hoặc một số; bạn sẽ thấy cách chúng tôi sử dụng nó trong bước webhooks

Đoạn mã trên trước tiên nhập các biến môi trường hiện tại và hủy chúng, sau đó thêm các biến môi trường mới và xuất kết hợp của cả hai dưới dạng một đối tượng.

Trong tệp ./app.jstệp, hãy chèn mã dưới đây:

process.env = require('./.env.js')(process.env.NODE_ENV || 'development');
const port = process.env.PORT || 9000;
const express = require('express');

let indexRoutes = require('./routes/index.js');

const main = async () => {
    const app = express();
    app.use(express.json());
    app.use(express.urlencoded({ extended: false }));
    app.use('/', indexRoutes);
    app.use('*', (req, res) => res.status(404).send('404 Not Found'));
    app.listen(port, () =>
        console.log(`App now running and listening on port ${port}`)
    );
};
main();

Dòng đầu tiên của khối mã ở trên chỉ cần nhập ./.env.jstệp và gán tệp cho nó process.env, đây là một đối tượng có thể truy cập toàn cầu trong Node.js.

Trong tệp ./routes/index.js, hãy chèn mã dưới đây:

'use strict';
const router = require('express').Router();

router.get('/meta_wa_callbackurl', (req, res) => {
    try {
        console.log('GET: Someone is pinging me!');

        let mode = req.query['hub.mode'];
        let token = req.query['hub.verify_token'];
        let challenge = req.query['hub.challenge'];

        if (
            mode &&
            token &&
            mode === 'subscribe' &&
            process.env.Meta_WA_VerifyToken === token
        ) {
            return res.status(200).send(challenge);
        } else {
            return res.sendStatus(403);
        }
    } catch (error) {
        console.error({error})
        return res.sendStatus(500);
    }
});

router.post('/meta_wa_callbackurl', async (req, res) => {
    try {
        console.log('POST: Someone is pinging me!');
        return res.sendStatus(200);
    } catch (error) {
                console.error({error})
        return res.sendStatus(500);
    }
});
module.exports = router;

Tiếp theo, mở thiết bị đầu cuối và chạy:

nodemon app.js

Máy chủ Express sẽ chạy trên cổng 9000.

Tiếp theo, mở một thiết bị đầu cuối khác, riêng biệt và chạy:

ngrok http 9000

Lệnh này hiển thị ứng dụng Express của chúng tôi với internet rộng lớn hơn. Mục tiêu ở đây là thiết lập một webhook mà WhatsApp Cloud có thể ping.

Lưu ý URL mà ngrok chỉ định cho máy chủ Express của bạn. Trong ví dụ của tôi, ngrok đã cấp cho tôi URL này https://7b9b-102-219-204-54.ngrok.io:. Giữ cho cả máy chủ Express và thiết bị đầu cuối ngrok chạy.

Tiếp theo, hãy tiếp tục công việc của chúng ta trong bảng điều khiển Meta Developer. Cuộn đến phần có tiêu đề Định cấu hình Webhooks để nhận tin nhắn và nhấp vào Định cấu hình Webhooks . Liên kết sẽ hiển thị một trang giống như ảnh chụp màn hình bên dưới:

Trang cấu hình webhooks

Nhấp vào nút Chỉnh sửa và một cửa sổ bật lên sẽ hiển thị.

Trong trường URL gọi lại , hãy dán URL mà ngrok đã cấp cho bạn và nối nó với tuyến gọi lại, như trong lệnh ./routes/index.js. URL đầy đủ của tôi, trong trường hợp này, là https://7b9b-102-219-204-54.ngrok.io/meta_wa_callbackurl.

Trong trường Xác minh mã thông báo , hãy nhập giá trị của Meta_WA_VerifyToken khi nó xuất hiện trong ./.env.jstệp của bạn.

Nhập giá trị vào trường mã thông báo xác minh

Sau đó nhấp vào Xác minh và lưu .

Nếu bạn đã định cấu hình điều này tốt, bạn sẽ thấy một console.logthông báo trong thiết bị đầu cuối của máy chủ Express cho biết:

GET: Ai đó đang ping tôi!

Định cấu hình máy chủ Express của chúng tôi

Bây giờ, hãy làm cho máy chủ Express của chúng tôi nhận tin nhắn đăng ký từ Meta.

Trên cùng một màn hình bảng điều khiển Meta Developers, nhấp vào Quản lý và một cửa sổ bật lên sẽ xuất hiện.

Quản lý cửa sổ bật lên thông báo đăng ký máy chủ nhanh

Chọn Tin nhắn và nhấp vào Kiểm tra , trên cùng một hàng.

Bạn sẽ thấy một console.logthông báo trong thiết bị đầu cuối của máy chủ Express có nội dung:

BÀI ĐĂNG: Ai đó đang ping tôi!

Nếu bạn thấy thông báo này, hãy quay lại cùng một cửa sổ bật lên và nhấp vào Đăng ký trong cùng một hàng thông báo. Sau đó, nhấp vào Xong .

Bước 3: Viết logic kinh doanh của chúng tôi

Định cấu hình nguồn dữ liệu thương mại điện tử

Đầu tiên, chúng tôi sẽ thiết lập logic của mình để tìm nạp dữ liệu từ FakeStoreAPI, tạo hóa đơn PDF và tạo địa điểm nhận đơn đặt hàng giả. Chúng tôi sẽ gói logic này thành một lớp JavaScript, sau đó chúng tôi sẽ nhập vào logic của ứng dụng.

Tạo một tệp và đặt tên cho nó ./utils/ecommerce_store.js. Trong tệp này, hãy dán mã sau:

'use strict';
const request = require('request');
const PDFDocument = require('pdfkit');
const fs = require('fs');

module.exports = class EcommerceStore {
    constructor() {}
    async _fetchAssistant(endpoint) {
        return new Promise((resolve, reject) => {
            request.get(
                `https://fakestoreapi.com${endpoint ? endpoint : '/'}`,
                (error, res, body) => {
                    try {
                        if (error) {
                            reject(error);
                        } else {
                            resolve({
                                status: 'success',
                                data: JSON.parse(body),
                            });
                        }
                    } catch (error) {
                        reject(error);
                    }
                }
            );
        });
    }

    async getProductById(productId) {
        return await this._fetchAssistant(`/products/${productId}`);
    }
    async getAllCategories() {
        return await this._fetchAssistant('/products/categories?limit=100');
    }
    async getProductsInCategory(categoryId) {
        return await this._fetchAssistant(
            `/products/category/${categoryId}?limit=10`
        );
    }

    generatePDFInvoice({ order_details, file_path }) {
        const doc = new PDFDocument();
        doc.pipe(fs.createWriteStream(file_path));
        doc.fontSize(25);
        doc.text(order_details, 100, 100);
        doc.end();
        return;
    }

    generateRandomGeoLocation() {
        let storeLocations = [
            {
                latitude: 44.985613,
                longitude: 20.1568773,
                address: 'New Castle',
            },
            {
                latitude: 36.929749,
                longitude: 98.480195,
                address: 'Glacier Hill',
            },
            {
                latitude: 28.91667,
                longitude: 30.85,
                address: 'Buena Vista',
            },
        ];
        return storeLocations[
            Math.floor(Math.random() * storeLocations.length)
        ];
    }
};

Trong đoạn mã trên, chúng ta đã tạo một lớp được gọi là EcommerceStore.

Phương thức đầu tiên _fetchAssistant, nhận một điểm cuối mà nó sử dụng để ping fakestoreapi.com .

Các phương thức sau hoạt động như trình tạo truy vấn cho phương thức đầu tiên:

  1. getProductById nhận ID sản phẩm và sau đó nhận dữ liệu liên quan đến sản phẩm cụ thể đó
  2. getAllCategories tìm nạp tất cả các danh mục có trong fakestoreapi.com
  3. getProductsInCategory nhận một danh mục sản phẩm và sau đó tiến hành tìm nạp tất cả các sản phẩm trong danh mục cụ thể đó

Các trình xây dựng truy vấn này sẽ gọi phương thức đầu tiên.

Tiếp tục, phương thức generatePDFInvoice nhận một đoạn văn bản và một đường dẫn tệp. Sau đó, nó tạo một tài liệu PDF, viết văn bản trên đó và sau đó lưu trữ tài liệu trong đường dẫn tệp được cung cấp.

Phương thức này generateRandomGeoLocation chỉ trả về một vị trí địa lý ngẫu nhiên. Phương pháp này sẽ hữu ích khi chúng tôi gửi địa điểm nhận đơn hàng của shop cho khách hàng muốn lấy hàng của họ.

Định cấu hình phiên khách hàng

Để xử lý hành trình của khách hàng, chúng tôi cần giữ một phiên bao gồm hồ sơ khách hàng và giỏ hàng của họ. Do đó, mỗi khách hàng sẽ có phiên duy nhất của riêng họ.

Trong quá trình sản xuất, chúng tôi có thể sử dụng cơ sở dữ liệu như MySQL, MongoDB hoặc một thứ gì đó khác có khả năng phục hồi, nhưng để giữ cho hướng dẫn của chúng tôi gọn gàng và ngắn gọn, chúng tôi sẽ sử dụng cấu trúc dữ liệu của ES2015Map . Với Map, chúng tôi có thể lưu trữ và truy xuất dữ liệu cụ thể, có thể lặp lại, chẳng hạn như dữ liệu khách hàng duy nhất.

Trong ./routes/index.jstệp của bạn, hãy thêm đoạn mã sau ngay bên trên router.get('/meta_wa_callbackurl', (req, res).

const EcommerceStore = require('./../utils/ecommerce_store.js');
let Store = new EcommerceStore();
const CustomerSession = new Map();

router.get('/meta_wa_callbackurl', (req, res) => {//this line already exists. Add the above lines

Dòng đầu tiên nhập EcommerceStorelớp, trong khi dòng thứ hai khởi tạo nó. Dòng thứ ba tạo phiên của khách hàng mà chúng tôi sẽ sử dụng để lưu trữ hành trình của khách hàng.

Khởi tạo API đám mây WhatsApp của chúng tôi

Nhớ whatsappcloudapi_wrappergói mà chúng tôi đã cài đặt trước đó? Đã đến lúc nhập và khởi tạo nó.

Trong ./routes/index.jstệp, hãy thêm các dòng mã sau vào bên dưới khai báo bộ định tuyến Express:

const router = require('express').Router(); // This line already exists. Below it add  the following lines:

const WhatsappCloudAPI = require('whatsappcloudapi_wrapper');
const Whatsapp = new WhatsappCloudAPI({
    accessToken: process.env.Meta_WA_accessToken,
    senderPhoneNumberId: process.env.Meta_WA_SenderPhoneNumberId,
    WABA_ID: process.env.Meta_WA_wabaId,
});

Các giá trị sau là các biến môi trường mà chúng tôi đã xác định trong ./.env.jstệp của mình:

  • process.env.Meta_WA_accessToken
  • process.env.Meta_WA_SenderPhoneNumberId
  • process.env.Meta_WA_wabaId

Chúng tôi khởi tạo lớp WhatsAppCloudAPI với ba giá trị ở trên và đặt tên cho phiên bản của chúng tôi Whatsapp.

Tiếp theo, hãy phân tích cú pháp tất cả dữ liệu được đưa vào /meta_wa_callbackurlwebhook POST. Bằng cách phân tích cú pháp nội dung của các yêu cầu, chúng tôi sẽ có thể trích xuất tin nhắn và các chi tiết khác, như tên của người gửi, số điện thoại của người gửi, v.v.

Xin lưu ý : Tất cả các chỉnh sửa mã mà chúng tôi thực hiện từ thời điểm này sẽ hoàn toàn được thực hiện trong ./routes/index.jstệp.

Thêm các dòng mã sau vào bên dưới dấu ngoặc mở của try{câu lệnh:

try { // This line already exists. Add the below lines

        let data = Whatsapp.parseMessage(req.body);

        if (data?.isMessage) {
            let incomingMessage = data.message;
            let recipientPhone = incomingMessage.from.phone; // extract the phone number of sender
            let recipientName = incomingMessage.from.name;
            let typeOfMsg = incomingMessage.type; // extract the type of message (some are text, others are images, others are responses to buttons etc...)
            let message_id = incomingMessage.message_id; // extract the message id
        }

Bây giờ, khi khách hàng gửi tin nhắn cho chúng tôi, webhook của chúng tôi sẽ nhận được tin nhắn đó. Tin nhắn được chứa trong phần nội dung yêu cầu của webhook. Để trích xuất thông tin hữu ích ra khỏi phần nội dung của yêu cầu, chúng tôi cần chuyển phần nội dung đó vào parseMessagephương thức của phiên bản WhatsApp.

Sau đó, sử dụng một ifcâu lệnh, chúng tôi kiểm tra xem kết quả của phương pháp có chứa một tin nhắn WhatsApp hợp lệ hay không.

Bên trong ifcâu lệnh, chúng tôi xác định incomingMessage, có chứa thông báo. Chúng tôi cũng xác định các biến khác:

  • recipientPhonelà số của khách hàng đã gửi tin nhắn cho chúng tôi. Chúng tôi sẽ gửi cho họ một tin nhắn trả lời, do đó có tiền tố "người nhận"
  • recipientNamelà tên của khách hàng đã gửi tin nhắn cho chúng tôi. Đây là tên họ đã đặt cho mình trong hồ sơ WhatsApp của họ
  • typeOfMsglà loại tin nhắn mà một khách hàng đã gửi cho chúng tôi. Như chúng ta sẽ thấy ở phần sau, một số tin nhắn là văn bản đơn giản, trong khi những tin nhắn khác là trả lời cho các nút (đừng lo lắng, điều này sẽ sớm có ý nghĩa!)
  • message_idlà một chuỗi ký tự xác định duy nhất một tin nhắn mà chúng tôi đã nhận được. Điều này hữu ích khi chúng tôi muốn thực hiện các tác vụ cụ thể cho thư đó, chẳng hạn như đánh dấu thư là đã đọc

Cho đến thời điểm này, tất cả đều có vẻ ổn, nhưng chúng tôi sẽ xác nhận ngay sau đây.

Hiểu và đáp ứng ý định của khách hàng

Vì hướng dẫn của chúng tôi sẽ không đi sâu vào bất kỳ hình thức xử lý AI hoặc ngôn ngữ tự nhiên (NLP) nào, chúng tôi sẽ xác định luồng trò chuyện của mình bằng if…elselogic đơn giản.

Logic hội thoại bắt đầu khi khách hàng gửi tin nhắn văn bản. Chúng tôi sẽ không xem xét bản thân thông báo, vì vậy chúng tôi sẽ không biết họ định làm gì, nhưng chúng tôi có thể cho khách hàng biết bot của chúng tôi có thể làm gì.

Hãy cung cấp cho khách hàng một ngữ cảnh đơn giản để họ có thể trả lời với một mục đích cụ thể.

Chúng tôi sẽ cung cấp cho khách hàng hai nút:

  1. Một cho chúng tôi biết họ muốn nói chuyện với một con người thực tế, không phải một chatbot
  2. Một cái khác để duyệt sản phẩm

Để thực hiện việc này, hãy chèn đoạn mã sau vào bên dưới message_id:

if (typeOfMsg === 'text_message') {
    await Whatsapp.sendSimpleButtons({
        message: `Hey ${recipientName}, \nYou are speaking to a chatbot.\nWhat do you want to do next?`,
        recipientPhone: recipientPhone, 
        listOfButtons: [
            {
                title: 'View some products',
                id: 'see_categories',
            },
            {
                title: 'Speak to a human',
                id: 'speak_to_human',
            },
        ],
    });
}

Tuyên bố trên ifchỉ cho phép chúng tôi xử lý tin nhắn văn bản.

Phương sendSimpleButtonspháp này cho phép chúng tôi gửi các nút tới khách hàng. Ghi chú về các thuộc tính titleid. Đó là những gì khách titlehàng sẽ thấy và idlà những gì chúng tôi sẽ sử dụng để biết khách hàng đã nhấp vào nút nào.

Hãy kiểm tra xem chúng tôi đã làm điều này đúng. Mở ứng dụng WhatsApp của bạn và gửi tin nhắn văn bản đến tài khoản doanh nghiệp WhatsApp.

Gửi tin nhắn văn bản đến tài khoản doanh nghiệp WhatsApp

Nếu bạn nhận được phản hồi như ảnh chụp màn hình ở trên, xin chúc mừng! Bạn vừa gửi tin nhắn đầu tiên của mình qua API đám mây WhatsApp.

Vì khách hàng có thể nhấp vào một trong hai nút, chúng ta hãy quan tâm đến nút Nói với một người .

Bên ngoài ifcâu lệnh text_messagelogic, hãy chèn đoạn mã sau:

if (typeOfMsg === 'simple_button_message') {
    let button_id = incomingMessage.button_reply.id;

    if (button_id === 'speak_to_human') {
        await Whatsapp.sendText({
            recipientPhone: recipientPhone,
            message: `Arguably, chatbots are faster than humans.\nCall my human with the below details:`,
        });

        await Whatsapp.sendContact({
            recipientPhone: recipientPhone,
            contact_profile: {
                addresses: [
                    {
                        city: 'Nairobi',
                        country: 'Kenya',
                    },
                ],
                name: {
                    first_name: 'Daggie',
                    last_name: 'Blanqx',
                },
                org: {
                    company: 'Mom-N-Pop Shop',
                },
                phones: [
                    {
                        phone: '+1 (555) 025-3483',
                    },
                                        {
                        phone: '+254712345678',
                    },
                ],
            },
        });
    }
};

Đoạn mã trên thực hiện hai hành động:

  1. Gửi tin nhắn văn bản để cho người dùng biết rằng họ sẽ nhận được thẻ liên hệ, sử dụng sendTextphương pháp này
  2. Gửi thẻ liên hệ bằng sendContactphương thức này

Mã này cũng phát hiện ý định của người dùng bằng cách sử dụng ID của nút mà người dùng đã nhấp vào (trong trường hợp của chúng tôi, ID là incomingMessage.button_reply.id), và sau đó nó phản hồi với hai tùy chọn hành động.

Bây giờ, quay lại WhatsApp và nhấp vào Nói chuyện với con người . Nếu bạn làm đúng, bạn sẽ thấy một câu trả lời như sau:

Gửi "Nói chuyện với con người" và nhận tệp đính kèm liên hệ

Khi bạn nhấp vào thẻ liên hệ bạn nhận được, bạn sẽ thấy như sau:

Thẻ liên hệ hiển thị đầy đủ tên, doanh nghiệp và hai số điện thoại

Tiếp theo, chúng ta hãy làm việc trên nút Xem một số sản phẩm .

Bên trong simple_button_message ifcâu lệnh, nhưng ngay bên dưới và bên ngoài speak_to_human ifcâu lệnh, hãy thêm đoạn mã sau:

if (button_id === 'see_categories') {
    let categories = await Store.getAllCategories(); 
    await Whatsapp.sendSimpleButtons({
        message: `We have several categories.\nChoose one of them.`,
        recipientPhone: recipientPhone, 
        listOfButtons: categories.data
            .map((category) => ({
                title: category,
                id: `category_${category}`,
            }))
            .slice(0, 3)
    });
}

Đây là những gì đoạn mã trên thực hiện:

  1. Tuyên bố đảm bảo rằng người ifdùng đã nhấp vào nút Xem một số sản phẩm
  2. Tìm nạp danh mục sản phẩm từ FakeStoreAPIphương getAllCategoriesthức
  3. Giới hạn số lượng nút là ba bằng cách sử dụng phương pháp mảng - slice(0,3)- vì WhatsApp chỉ cho phép chúng tôi gửi ba nút đơn giản
  4. Sau đó, nó lặp lại từng danh mục, tạo một nút có một title và một ID duy nhất được bắt đầu bằngcategory_
  5. Với sendSimpleButtonsphương pháp, chúng tôi gửi các nút này cho khách hàng

Quay lại ứng dụng WhatsApp của bạn một lần nữa và nhấp vào Xem các sản phẩm khác . Nếu bạn đã làm đúng các bước trên, bạn sẽ thấy câu trả lời giống như ảnh chụp màn hình bên dưới:

Gửi "xem một số sản phẩm" trong trò chuyện WhatsApp

Tìm nạp sản phẩm theo danh mục

Bây giờ, chúng ta hãy tạo logic để có được sản phẩm trong danh mục mà khách hàng đã chọn.

Vẫn bên trong simple_button_message ifcâu lệnh, nhưng bên dưới và bên ngoài see_categories ifcâu lệnh, hãy thêm mã sau:

if (button_id.startsWith('category_')) {
    let selectedCategory = button_id.split('category_')[1];
    let listOfProducts = await Store.getProductsInCategory(selectedCategory);

    let listOfSections = [
        {
            title: ` Top 3: ${selectedCategory}`.substring(0,24),
            rows: listOfProducts.data
                .map((product) => {
                    let id = `product_${product.id}`.substring(0,256);
                    let title = product.title.substring(0,21);
                    let description = `${product.price}\n${product.description}`.substring(0,68);
                   
                    return {
                        id,
                        title: `${title}...`,
                        description: `$${description}...`
                    };
                }).slice(0, 10)
        },
    ];

    await Whatsapp.sendRadioButtons({
        recipientPhone: recipientPhone,
        headerText: `#BlackFriday Offers: ${selectedCategory}`,
        bodyText: `Our Santa  has lined up some great products for you based on your previous shopping history.\n\nPlease select one of the products below:`,
        footerText: 'Powered by: BMI LLC',
        listOfSections,
    });
}

ifTuyên bố trên xác nhận rằng nút mà khách hàng nhấp vào thực sự là nút có chứa một danh mục .

Điều đầu tiên chúng tôi làm ở đây là trích xuất danh mục cụ thể từ ID của nút. Sau đó, chúng tôi truy vấn FakeStoreAPI của chúng tôi để tìm các sản phẩm thuộc danh mục cụ thể đó.

Sau khi truy vấn, chúng tôi nhận được danh sách các sản phẩm bên trong một mảng , listOfProducts.data. Bây giờ chúng tôi lặp lại mảng này và đối với mỗi sản phẩm trong đó, chúng tôi trích xuất giá, tiêu đề, mô tả và ID của nó.

Chúng tôi thêm product_vào id, điều này sẽ giúp chúng tôi chọn lựa của khách hàng trong bước tiếp theo. Đảm bảo bạn cắt bớt độ dài của ID, tiêu đề và mô tả theo các hạn chế về nút radio (hoặc danh sách) của WhatsApp Cloud API .

Sau đó, chúng tôi trả về ba giá trị: ID, tiêu đề và mô tả. Vì WhatsApp chỉ cho phép chúng tôi tối đa 10 hàng, chúng tôi sẽ giới hạn số lượng sản phẩm là 10 bằng cách sử dụng phương pháp mảng .slice(0,10).

Sau đó, chúng tôi gọi sendRadioButtonsphương thức để gửi sản phẩm cho khách hàng. Ghi lại các thuộc tính , và . headerTextbodyTextfooterTextlistOfSections

Quay lại ứng dụng WhatsApp và nhấp vào bất kỳ danh mục sản phẩm nào. Nếu bạn đã làm theo đúng hướng dẫn, bạn sẽ thấy câu trả lời giống như ảnh chụp màn hình bên dưới:

Chọn danh mục điện tử và nhận phản hồi

Khi bạn nhấp vào Chọn một sản phẩm , bạn sẽ thấy màn hình sau:

Chọn một màn hình bật lên của sản phẩmTại thời điểm này, khách hàng có thể chọn một sản phẩm mà họ cảm thấy thú vị, nhưng liệu chúng ta có thể biết họ đã chọn những gì? Vẫn chưa, vì vậy hãy để chúng tôi làm việc trên phần này.

Bên ngoài simple_button_message ifcâu lệnh, hãy để chúng tôi thêm một ifcâu lệnh khác:

if (typeOfMsg === 'radio_button_message') {
    let selectionId = incomingMessage.list_reply.id; // the customer clicked and submitted a radio button
    
}

Bên trong ifcâu lệnh trên và ngay bên dưới câu lệnh selectionId, hãy thêm đoạn mã sau:

if (selectionId.startsWith('product_')) {
    let product_id = selectionId.split('_')[1];
    let product = await Store.getProductById(product_id);
    const { price, title, description, category, image: imageUrl, rating } = product.data;

    let emojiRating = (rvalue) => {
        rvalue = Math.floor(rvalue || 0); // generate as many star emojis as whole number ratings
        let output = [];
        for (var i = 0; i < rvalue; i++) output.push('');
        return output.length ? output.join('') : 'N/A';
    };

    let text = `_Title_: *${title.trim()}*\n\n\n`;
    text += `_Description_: ${description.trim()}\n\n\n`;
    text += `_Price_: $${price}\n`;
    text += `_Category_: ${category}\n`;
    text += `${rating?.count || 0} shoppers liked this product.\n`;
    text += `_Rated_: ${emojiRating(rating?.rate)}\n`;

    await Whatsapp.sendImage({
        recipientPhone,
        url: imageUrl,
        caption: text,
    });

    await Whatsapp.sendSimpleButtons({
        message: `Here is the product, what do you want to do next?`,
        recipientPhone: recipientPhone, 
        listOfButtons: [
            {
                title: 'Add to cart',
                id: `add_to_cart_${product_id}`,
            },
            {
                title: 'Speak to a human',
                id: 'speak_to_human',
            },
            {
                title: 'See more products',
                id: 'see_categories',
            },
        ],
    });
}

Đoạn mã trên thực hiện những việc sau:

  1. Trích xuất ID sản phẩm từ nút radio mà khách hàng đã nhấp vào
  2. Truy vấn FakeStoreAPI với ID sản phẩm đó
  3. Khi nhận và trích xuất dữ liệu của sản phẩm, nó sẽ định dạng văn bản. WhatsApp sử dụng dấu gạch dưới để hiển thị văn bản in nghiêng, trong khi dấu hoa thị hiển thị văn bản in đậm
  4. Hiển thị biểu tượng cảm xúc ngôi sao bằng cách sử dụng emojiRatingchức năng. Nếu xếp hạng là 3,8, nó sẽ hiển thị biểu tượng cảm xúc ba sao
  5. Đính kèm hình ảnh của sản phẩm vào văn bản được hiển thị và gửi nó bằng sendImagephương thức

Sau đó, chúng tôi gửi cho khách hàng danh sách ba nút bằng cách sử dụng sendSimpleButtons. Một cung cấp cho khách hàng cơ hội để thêm sản phẩm vào giỏ hàng của họ. Hãy lưu ý đến ID của nút có tiền tố add_to_cart_.

Bây giờ, quay lại ứng dụng WhatsApp của bạn và chọn một sản phẩm. Nếu bạn đã làm theo đúng hướng dẫn, bạn sẽ thấy câu trả lời giống như ảnh chụp màn hình sau:

Chatbot gửi cho khách hàng ba nút có thể lựa chọn

Phiên xây dựng để lưu trữ giỏ hàng của khách hàng

Để theo dõi các sản phẩm mà khách hàng thêm vào giỏ hàng của họ, chúng tôi cần có một nơi để lưu trữ các mặt hàng trong giỏ hàng. Đây là nơi CustomerSessionphát huy tác dụng. Hãy thêm một số logic vào nó.

Bên ngoài radio_button_message ifcâu lệnh và ngay bên dưới phần message_idkhai báo, hãy thêm đoạn mã sau:

let message_id = incomingMessage.message_id; // This line already exists. Add the below lines...

// Start of cart logic
if (!CustomerSession.get(recipientPhone)) {
    CustomerSession.set(recipientPhone, {
        cart: [],
    });
}

let addToCart = async ({ product_id, recipientPhone }) => {
    let product = await Store.getProductById(product_id);
    if (product.status === 'success') {
        CustomerSession.get(recipientPhone).cart.push(product.data);
    }
};

let listOfItemsInCart = ({ recipientPhone }) => {
    let total = 0;
    let products = CustomerSession.get(recipientPhone).cart;
    total = products.reduce(
        (acc, product) => acc + product.price,
        total
    );
    let count = products.length;
    return { total, products, count };
};

let clearCart = ({ recipientPhone }) => {
    CustomerSession.get(recipientPhone).cart = [];
};
// End of cart logic

if (typeOfMsg === 'text_message') { ... // This line already exists. Add the above lines...

Đoạn mã trên kiểm tra xem phiên của khách hàng đã được tạo hay chưa. Nếu nó chưa được tạo, nó sẽ tạo một phiên mới được nhận dạng duy nhất bởi số điện thoại của khách hàng. Sau đó, chúng tôi khởi tạo một thuộc tính được gọi cart, bắt đầu dưới dạng một mảng trống.

Hàm addToCartnhận a product_idvà số lượng khách hàng cụ thể. Sau đó, nó ping FakeStoreAPI để biết dữ liệu của sản phẩm cụ thể và đẩy sản phẩm vào cartmảng.

Sau đó, listOfItemsInCart hàm này lấy số điện thoại của khách hàng và truy xuất số điện thoại được liên kết cart, được sử dụng để tính số lượng sản phẩm trong giỏ hàng và tổng giá của chúng. Cuối cùng, nó trả về các mặt hàng trong giỏ hàng và tổng giá của chúng.

Chức clearCartnăng lấy số điện thoại của khách hàng và chuyển vào giỏ hàng của khách hàng đó.

Với logic giỏ hàng được thực hiện, hãy xây dựng nút Thêm vào giỏ hàng . Bên trong simple_button_message ifcâu lệnh và bên dưới phần button_idkhai báo, hãy thêm đoạn mã sau:

if (button_id.startsWith('add_to_cart_')) {
    let product_id = button_id.split('add_to_cart_')[1];
    await addToCart({ recipientPhone, product_id });
    let numberOfItemsInCart = listOfItemsInCart({ recipientPhone }).count;

    await Whatsapp.sendSimpleButtons({
        message: `Your cart has been updated.\nNumber of items in cart: ${numberOfItemsInCart}.\n\nWhat do you want to do next?`,
        recipientPhone: recipientPhone, 
        listOfButtons: [
            {
                title: 'Checkout ',
                id: `checkout`,
            },
            {
                title: 'See more products',
                id: 'see_categories',
            },
        ],
    });
}

Đoạn mã trên trích xuất ID sản phẩm từ nút khách hàng nhấp vào, sau đó gọi addToCartchức năng lưu sản phẩm vào giỏ hàng của phiên khách hàng. Sau đó, nó trích xuất số lượng mặt hàng trong giỏ hàng của phiên của khách hàng và cho khách hàng biết họ có bao nhiêu sản phẩm. Nó cũng gửi hai nút, một trong số đó cho phép người dùng kiểm tra.

Ghi lại ID nút và quay lại ứng dụng WhatsApp của bạn. Nhấp vào Thêm vào giỏ hàng . Nếu bạn làm theo đúng hướng dẫn, bạn sẽ thấy câu trả lời giống như ảnh chụp màn hình bên dưới:

Thêm vào giỏ hàng

Bây giờ khách hàng của chúng tôi có thể thêm các mặt hàng vào giỏ hàng, chúng tôi có thể viết logic để thanh toán.

Viết logic thanh toán

Bên trong simple_button_message ifcâu lệnh nhưng bên ngoài add_to_cart_ ifcâu lệnh, hãy thêm đoạn mã sau:

if (button_id === 'checkout') {
  let finalBill = listOfItemsInCart({ recipientPhone });
  let invoiceText = `List of items in your cart:\n`;

  finalBill.products.forEach((item, index) => {
      let serial = index + 1;
      invoiceText += `\n#${serial}: ${item.title} @ $${item.price}`;
  });

  invoiceText += `\n\nTotal: $${finalBill.total}`;

  Store.generatePDFInvoice({
      order_details: invoiceText,
      file_path: `./invoice_${recipientName}.pdf`,
  });

  await Whatsapp.sendText({
      message: invoiceText,
      recipientPhone: recipientPhone,
  });

  await Whatsapp.sendSimpleButtons({
      recipientPhone: recipientPhone,
      message: `Thank you for shopping with us, ${recipientName}.\n\nYour order has been received & will be processed shortly.`,
      message_id,
      listOfButtons: [
          {
              title: 'See more products',
              id: 'see_categories',
          },
          {
              title: 'Print my invoice',
              id: 'print_invoice',
          },
      ],
  });

  clearCart({ recipientPhone });
}

Đoạn mã trên thực hiện những việc sau:

  1. Nhận tất cả các mặt hàng trong giỏ hàng và đặt chúng vào bên trongfinalBill
  2. Khởi tạo một biến invoiceText, biến này sẽ chứa văn bản mà chúng tôi sẽ gửi cho khách hàng cũng như văn bản sẽ được soạn thảo thành phiên bản PDF của hóa đơn
    1. Vòng forEachlặp chỉ đơn giản là nối titlepricecủa từng sản phẩm với hóa đơn
  3. Phương generatePDFInvoicethức (giống phương thức mà chúng tôi đã xác định trong EcommerceStorelớp của mình) lấy chi tiết của đơn đặt hàng, soạn thảo tài liệu PDF và lưu nó vào đường dẫn tệp trong thư mục / thư mục cục bộ mà chúng tôi đã cung cấp
  4. Phương sendTextthức gửi một tin nhắn văn bản đơn giản chứa thông tin chi tiết về đơn đặt hàng cho khách hàng
  5. sendSimpleButtonsgửi một số nút cho khách hàng. Hãy lưu ý đến nút In hóa đơn của tôi và ID của nó
  6. Cuối cùng, clearCartphương pháp làm trống giỏ hàng

Bây giờ, hãy quay lại ứng dụng WhatsApp của bạn và nhấp vào Thanh toán . Nếu bạn làm theo đúng hướng dẫn, bạn sẽ thấy một câu trả lời giống như ảnh chụp màn hình sau:

Nhấp vào nút thanh toán

Tại thời điểm này, khách hàng sẽ nhận được hóa đơn PDF có thể in được. Vì lý do này, hãy để chúng tôi làm việc trên một số logic liên quan đến nút In hóa đơn của tôi .

Viết logic hóa đơn có thể in của chúng tôi

Bên trong simple_button_message ifcâu lệnh nhưng bên ngoài checkout ifcâu lệnh, hãy thêm đoạn mã sau:

if (button_id === 'print_invoice') {
  // Send the PDF invoice
  await Whatsapp.sendDocument({
      recipientPhone: recipientPhone,
      caption:`Mom-N-Pop Shop invoice #${recipientName}`
      file_path: `./invoice_${recipientName}.pdf`,
  });

  // Send the location of our pickup station to the customer, so they can come and pick up their order
  let warehouse = Store.generateRandomGeoLocation();

  await Whatsapp.sendText({
      recipientPhone: recipientPhone,
      message: `Your order has been fulfilled. Come and pick it up, as you pay, here:`,
  });

  await Whatsapp.sendLocation({
      recipientPhone,
      latitude: warehouse.latitude,
      longitude: warehouse.longitude,
      address: warehouse.address,
      name: 'Mom-N-Pop Shop',
  });
}

Đoạn mã trên lấy tài liệu PDF được tạo ở bước trước từ hệ thống tệp cục bộ và gửi cho khách hàng bằng sendDocumentphương pháp này.

Khi một khách hàng đặt mua một sản phẩm trực tuyến, họ cũng cần biết họ sẽ nhận được sản phẩm vật chất như thế nào. Vì lý do này, chúng tôi đã tạo một số tọa độ ngẫu nhiên bằng cách sử dụng generateRandomGeoLocationphương thức của EcommerceStorelớp và gửi các tọa độ này cho khách hàng bằng sendLocationphương pháp này để cho họ biết nơi họ có thể lấy sản phẩm của mình.

Bây giờ, hãy mở ứng dụng WhatsApp của bạn và nhấp vào In hóa đơn của tôi .

Nếu bạn đã làm theo đúng hướng dẫn ở trên, bạn sẽ thấy câu trả lời giống với ảnh chụp màn hình bên dưới:

Nhắn tin "in hóa đơn của tôi" và nhận tệp PDF và hướng dẫn lấy sản phẩm.

Hiển thị biên nhận đã đọc cho khách hàng

Cuối cùng, bạn có thể nhận thấy rằng các dấu kiểm bên dưới thư có màu xám thay vì màu xanh lam. Điều này cho thấy rằng các tin nhắn chúng tôi đã gửi không trả lại các xác nhận đã đọc mặc dù thực tế là bot của chúng tôi đang đọc chúng.

Những con bọ màu xám có thể gây khó chịu cho khách hàng và vì lý do này, chúng tôi cần làm việc để hiển thị những con bọ màu xanh lam.

Bên ngoài simple_button_message ifcâu lệnh và trước dấu ngoặc nhọn đóng của data?.isMessage ifcâu lệnh, hãy thêm đoạn mã sau:

await Whatsapp.markMessageAsRead({ message_id });

Một dòng chữ đơn giản này đánh dấu một tin nhắn được đọc ngay sau khi chúng tôi trả lời nó.

Bây giờ, hãy mở ứng dụng WhatsApp của bạn và gửi một tin nhắn văn bản ngẫu nhiên. Bạn có thấy những gì tôi đang thấy không?

Tin nhắn "hey" và chatbot trả lời bằng tin nhắn mặc định

Nếu các cuộc trò chuyện trước đó của bạn đã được cập nhật bằng dấu tích màu xanh, thì xin chúc mừng! Bạn đã xem đến phần cuối của hướng dẫn này và học được một số điều trong suốt quá trình.

Suy nghĩ cuối cùng

Với tổng số 2 tỷ người dùng hoạt động hàng tháng, việc bỏ qua WhatsApp như một chiến lược thương mại điện tử là một cách chắc chắn để tụt hậu so với đối thủ cạnh tranh của doanh nghiệp bạn và vì hầu hết khách hàng của bạn đã sử dụng WhatsApp trong các hoạt động hàng ngày của họ, tại sao không nên ' doanh nghiệp của bạn có gặp họ ở đó không?

Tôi hy vọng hướng dẫn này sẽ hữu ích trong việc làm sáng tỏ API đám mây WhatsApp và tôi hy vọng bạn đã có một chút thú vị trong suốt quá trình này. Hãy cho tôi biết những chủ đề khác mà bạn có thể thấy thú vị và đừng quên chia sẻ bài viết này với giới công nghệ của bạn.

 Nguồn: https://blog.logrocket.com/build-ecommerce-app-whatsapp-cloud-api-node-js/

#whatsapp #ecommerce #cloud #api #nodejs 

Adaline  Kulas

Adaline Kulas

1594162500

Multi-cloud Spending: 8 Tips To Lower Cost

A multi-cloud approach is nothing but leveraging two or more cloud platforms for meeting the various business requirements of an enterprise. The multi-cloud IT environment incorporates different clouds from multiple vendors and negates the dependence on a single public cloud service provider. Thus enterprises can choose specific services from multiple public clouds and reap the benefits of each.

Given its affordability and agility, most enterprises opt for a multi-cloud approach in cloud computing now. A 2018 survey on the public cloud services market points out that 81% of the respondents use services from two or more providers. Subsequently, the cloud computing services market has reported incredible growth in recent times. The worldwide public cloud services market is all set to reach $500 billion in the next four years, according to IDC.

By choosing multi-cloud solutions strategically, enterprises can optimize the benefits of cloud computing and aim for some key competitive advantages. They can avoid the lengthy and cumbersome processes involved in buying, installing and testing high-priced systems. The IaaS and PaaS solutions have become a windfall for the enterprise’s budget as it does not incur huge up-front capital expenditure.

However, cost optimization is still a challenge while facilitating a multi-cloud environment and a large number of enterprises end up overpaying with or without realizing it. The below-mentioned tips would help you ensure the money is spent wisely on cloud computing services.

  • Deactivate underused or unattached resources

Most organizations tend to get wrong with simple things which turn out to be the root cause for needless spending and resource wastage. The first step to cost optimization in your cloud strategy is to identify underutilized resources that you have been paying for.

Enterprises often continue to pay for resources that have been purchased earlier but are no longer useful. Identifying such unused and unattached resources and deactivating it on a regular basis brings you one step closer to cost optimization. If needed, you can deploy automated cloud management tools that are largely helpful in providing the analytics needed to optimize the cloud spending and cut costs on an ongoing basis.

  • Figure out idle instances

Another key cost optimization strategy is to identify the idle computing instances and consolidate them into fewer instances. An idle computing instance may require a CPU utilization level of 1-5%, but you may be billed by the service provider for 100% for the same instance.

Every enterprise will have such non-production instances that constitute unnecessary storage space and lead to overpaying. Re-evaluating your resource allocations regularly and removing unnecessary storage may help you save money significantly. Resource allocation is not only a matter of CPU and memory but also it is linked to the storage, network, and various other factors.

  • Deploy monitoring mechanisms

The key to efficient cost reduction in cloud computing technology lies in proactive monitoring. A comprehensive view of the cloud usage helps enterprises to monitor and minimize unnecessary spending. You can make use of various mechanisms for monitoring computing demand.

For instance, you can use a heatmap to understand the highs and lows in computing visually. This heat map indicates the start and stop times which in turn lead to reduced costs. You can also deploy automated tools that help organizations to schedule instances to start and stop. By following a heatmap, you can understand whether it is safe to shut down servers on holidays or weekends.

#cloud computing services #all #hybrid cloud #cloud #multi-cloud strategy #cloud spend #multi-cloud spending #multi cloud adoption #why multi cloud #multi cloud trends #multi cloud companies #multi cloud research #multi cloud market

Top 10 API Security Threats Every API Team Should Know

As more and more data is exposed via APIs either as API-first companies or for the explosion of single page apps/JAMStack, API security can no longer be an afterthought. The hard part about APIs is that it provides direct access to large amounts of data while bypassing browser precautions. Instead of worrying about SQL injection and XSS issues, you should be concerned about the bad actor who was able to paginate through all your customer records and their data.

Typical prevention mechanisms like Captchas and browser fingerprinting won’t work since APIs by design need to handle a very large number of API accesses even by a single customer. So where do you start? The first thing is to put yourself in the shoes of a hacker and then instrument your APIs to detect and block common attacks along with unknown unknowns for zero-day exploits. Some of these are on the OWASP Security API list, but not all.

Insecure pagination and resource limits

Most APIs provide access to resources that are lists of entities such as /users or /widgets. A client such as a browser would typically filter and paginate through this list to limit the number items returned to a client like so:

First Call: GET /items?skip=0&take=10 
Second Call: GET /items?skip=10&take=10

However, if that entity has any PII or other information, then a hacker could scrape that endpoint to get a dump of all entities in your database. This could be most dangerous if those entities accidently exposed PII or other sensitive information, but could also be dangerous in providing competitors or others with adoption and usage stats for your business or provide scammers with a way to get large email lists. See how Venmo data was scraped

A naive protection mechanism would be to check the take count and throw an error if greater than 100 or 1000. The problem with this is two-fold:

  1. For data APIs, legitimate customers may need to fetch and sync a large number of records such as via cron jobs. Artificially small pagination limits can force your API to be very chatty decreasing overall throughput. Max limits are to ensure memory and scalability requirements are met (and prevent certain DDoS attacks), not to guarantee security.
  2. This offers zero protection to a hacker that writes a simple script that sleeps a random delay between repeated accesses.
skip = 0
while True:    response = requests.post('https://api.acmeinc.com/widgets?take=10&skip=' + skip),                      headers={'Authorization': 'Bearer' + ' ' + sys.argv[1]})    print("Fetched 10 items")    sleep(randint(100,1000))    skip += 10

How to secure against pagination attacks

To secure against pagination attacks, you should track how many items of a single resource are accessed within a certain time period for each user or API key rather than just at the request level. By tracking API resource access at the user level, you can block a user or API key once they hit a threshold such as “touched 1,000,000 items in a one hour period”. This is dependent on your API use case and can even be dependent on their subscription with you. Like a Captcha, this can slow down the speed that a hacker can exploit your API, like a Captcha if they have to create a new user account manually to create a new API key.

Insecure API key generation

Most APIs are protected by some sort of API key or JWT (JSON Web Token). This provides a natural way to track and protect your API as API security tools can detect abnormal API behavior and block access to an API key automatically. However, hackers will want to outsmart these mechanisms by generating and using a large pool of API keys from a large number of users just like a web hacker would use a large pool of IP addresses to circumvent DDoS protection.

How to secure against API key pools

The easiest way to secure against these types of attacks is by requiring a human to sign up for your service and generate API keys. Bot traffic can be prevented with things like Captcha and 2-Factor Authentication. Unless there is a legitimate business case, new users who sign up for your service should not have the ability to generate API keys programmatically. Instead, only trusted customers should have the ability to generate API keys programmatically. Go one step further and ensure any anomaly detection for abnormal behavior is done at the user and account level, not just for each API key.

Accidental key exposure

APIs are used in a way that increases the probability credentials are leaked:

  1. APIs are expected to be accessed over indefinite time periods, which increases the probability that a hacker obtains a valid API key that’s not expired. You save that API key in a server environment variable and forget about it. This is a drastic contrast to a user logging into an interactive website where the session expires after a short duration.
  2. The consumer of an API has direct access to the credentials such as when debugging via Postman or CURL. It only takes a single developer to accidently copy/pastes the CURL command containing the API key into a public forum like in GitHub Issues or Stack Overflow.
  3. API keys are usually bearer tokens without requiring any other identifying information. APIs cannot leverage things like one-time use tokens or 2-factor authentication.

If a key is exposed due to user error, one may think you as the API provider has any blame. However, security is all about reducing surface area and risk. Treat your customer data as if it’s your own and help them by adding guards that prevent accidental key exposure.

How to prevent accidental key exposure

The easiest way to prevent key exposure is by leveraging two tokens rather than one. A refresh token is stored as an environment variable and can only be used to generate short lived access tokens. Unlike the refresh token, these short lived tokens can access the resources, but are time limited such as in hours or days.

The customer will store the refresh token with other API keys. Then your SDK will generate access tokens on SDK init or when the last access token expires. If a CURL command gets pasted into a GitHub issue, then a hacker would need to use it within hours reducing the attack vector (unless it was the actual refresh token which is low probability)

Exposure to DDoS attacks

APIs open up entirely new business models where customers can access your API platform programmatically. However, this can make DDoS protection tricky. Most DDoS protection is designed to absorb and reject a large number of requests from bad actors during DDoS attacks but still need to let the good ones through. This requires fingerprinting the HTTP requests to check against what looks like bot traffic. This is much harder for API products as all traffic looks like bot traffic and is not coming from a browser where things like cookies are present.

Stopping DDoS attacks

The magical part about APIs is almost every access requires an API Key. If a request doesn’t have an API key, you can automatically reject it which is lightweight on your servers (Ensure authentication is short circuited very early before later middleware like request JSON parsing). So then how do you handle authenticated requests? The easiest is to leverage rate limit counters for each API key such as to handle X requests per minute and reject those above the threshold with a 429 HTTP response. There are a variety of algorithms to do this such as leaky bucket and fixed window counters.

Incorrect server security

APIs are no different than web servers when it comes to good server hygiene. Data can be leaked due to misconfigured SSL certificate or allowing non-HTTPS traffic. For modern applications, there is very little reason to accept non-HTTPS requests, but a customer could mistakenly issue a non HTTP request from their application or CURL exposing the API key. APIs do not have the protection of a browser so things like HSTS or redirect to HTTPS offer no protection.

How to ensure proper SSL

Test your SSL implementation over at Qualys SSL Test or similar tool. You should also block all non-HTTP requests which can be done within your load balancer. You should also remove any HTTP headers scrub any error messages that leak implementation details. If your API is used only by your own apps or can only be accessed server-side, then review Authoritative guide to Cross-Origin Resource Sharing for REST APIs

Incorrect caching headers

APIs provide access to dynamic data that’s scoped to each API key. Any caching implementation should have the ability to scope to an API key to prevent cross-pollution. Even if you don’t cache anything in your infrastructure, you could expose your customers to security holes. If a customer with a proxy server was using multiple API keys such as one for development and one for production, then they could see cross-pollinated data.

#api management #api security #api best practices #api providers #security analytics #api management policies #api access tokens #api access #api security risks #api access keys

Autumn  Blick

Autumn Blick

1601381326

Public ASX100 APIs: The Essential List

We’ve conducted some initial research into the public APIs of the ASX100 because we regularly have conversations about what others are doing with their APIs and what best practices look like. Being able to point to good local examples and explain what is happening in Australia is a key part of this conversation.

Method

The method used for this initial research was to obtain a list of the ASX100 (as of 18 September 2020). Then work through each company looking at the following:

  1. Whether the company had a public API: this was found by googling “[company name] API” and “[company name] API developer” and “[company name] developer portal”. Sometimes the company’s website was navigated or searched.
  2. Some data points about the API were noted, such as the URL of the portal/documentation and the method they used to publish the API (portal, documentation, web page).
  3. Observations were recorded that piqued the interest of the researchers (you will find these below).
  4. Other notes were made to support future research.
  5. You will find a summary of the data in the infographic below.

Data

With regards to how the APIs are shared:

#api #api-development #api-analytics #apis #api-integration #api-testing #api-security #api-gateway

Adaline  Kulas

Adaline Kulas

1594166040

What are the benefits of cloud migration? Reasons you should migrate

The moving of applications, databases and other business elements from the local server to the cloud server called cloud migration. This article will deal with migration techniques, requirement and the benefits of cloud migration.

In simple terms, moving from local to the public cloud server is called cloud migration. Gartner says 17.5% revenue growth as promised in cloud migration and also has a forecast for 2022 as shown in the following image.

#cloud computing services #cloud migration #all #cloud #cloud migration strategy #enterprise cloud migration strategy #business benefits of cloud migration #key benefits of cloud migration #benefits of cloud migration #types of cloud migration