> ## Documentation Index
> Fetch the complete documentation index at: https://chatbotx.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Tích hợp Shopify qua MCP

> Hướng dẫn từng bước kết nối cửa hàng Shopify với AI Agent trên ChatbotX qua giao thức MCP để tự động tra cứu sản phẩm, tạo đơn hàng và xử lý hủy đơn.

**Shopify via MCP** là giải pháp kết nối trực tiếp cửa hàng trực tuyến Shopify với AI Agent trên ChatbotX thông qua giao thức tiêu chuẩn **Model Context Protocol (MCP)**.

Với thiết lập này, AI Agent của bạn sẽ trở thành một nhân viên bán hàng và chăm sóc khách hàng tự động 24/7 với đầy đủ năng lực:

* Tra cứu danh mục, kiểm tra tồn kho theo từng biến thể (size, màu sắc) theo thời gian thực.
* Tư vấn và hiển thị sản phẩm trực quan kèm nút bấm hành động.
* Tự động tạo hồ sơ khách hàng mới và đẩy đơn hàng chính thức vào trang quản trị Shopify Admin với địa chỉ chuẩn hóa (Address, City, Province).
* Tạo link thanh toán giỏ hàng tổng hợp cho nhiều sản phẩm cùng lúc.
* Tự động hủy đơn hàng trên hệ thống và hoàn trả số lượng tồn kho khi khách đổi ý.
* Tra cứu trạng thái thanh toán, tiến độ giao vận và mã vận đơn theo thời gian thực.

## Mô hình hoạt động

Hệ thống vận hành theo mô hình cầu nối 3 lớp khép kín:

1. **Khách hàng** tương tác trên các kênh nhắn tin (Facebook Messenger, Instagram, Webchat, WhatsApp, Zalo).
2. **AI Agent (ChatbotX)** phân tích ngôn ngữ tự nhiên và tự động gọi các công cụ MCP tương ứng.
3. **Shopify MCP Server** đóng vai trò cầu nối xử lý thông tin (chuẩn hóa số điện thoại, địa chỉ nhận hàng) và đồng bộ trực tiếp với hệ thống quản trị Shopify của bạn.

## Bước 1: Tạo ứng dụng trên Shopify Dev Dashboard

Để cấp quyền cho ChatbotX truy xuất sản phẩm và quản trị đơn hàng, bạn cần tạo một ứng dụng riêng trên trang quản trị Shopify:

<Steps>
  <Step title="Truy cập Develop apps từ Cài đặt Shopify">
    Từ trang quản trị Shopify của bạn, vào **Settings (Cài đặt)** ➔ chọn mục **Apps** ở menu bên trái ➔ nhấn nút **Develop apps** ở góc trên bên phải.
  </Step>
</Steps>

<Frame>
  <img src="https://mintcdn.com/chatbotx/fyHPACwNoMW_jXQO/images/shopify_settings_develop_apps.png?fit=max&auto=format&n=fyHPACwNoMW_jXQO&q=85&s=73d2e039403359be4065a4847bb6b8a7" alt="Shopify Settings Develop Apps" width="2266" height="1657" data-path="images/shopify_settings_develop_apps.png" />
</Frame>

<Steps>
  <Step title="Bắt đầu tạo ứng dụng trong Dev Dashboard">
    Tại giao diện Dev Dashboard, tìm đến mục *Get API credentials* và nhấn nút **Create app**.
  </Step>
</Steps>

<Frame>
  <img src="https://mintcdn.com/chatbotx/fyHPACwNoMW_jXQO/images/shopify_dev_dashboard_create_app.png?fit=max&auto=format&n=fyHPACwNoMW_jXQO&q=85&s=7417c3b9284d29144f943b9a34bf7055" alt="Shopify Dev Dashboard Create App" width="2989" height="1804" data-path="images/shopify_dev_dashboard_create_app.png" />
</Frame>

<Steps>
  <Step title="Đặt tên ứng dụng">
    Tại mục *Start from Dev Dashboard*, nhập tên gợi nhớ cho ứng dụng vào ô **App name** (ví dụ: `BotX MCP`) và nhấn nút **Create app**.
  </Step>
</Steps>

<Frame>
  <img src="https://mintcdn.com/chatbotx/fyHPACwNoMW_jXQO/images/shopify_create_app_name.png?fit=max&auto=format&n=fyHPACwNoMW_jXQO&q=85&s=bc288443c0c26f860a8f7bd953166fd8" alt="Shopify Create App Name" width="2989" height="1804" data-path="images/shopify_create_app_name.png" />
</Frame>

<Steps>
  <Step title="Mở bảng cấu hình quyền Scopes">
    Tại trang quản trị ứng dụng vừa tạo, cuộn đến phần **API access** và nhấn vào chữ **Select scopes** màu xanh bên cạnh mục Scopes.
  </Step>
</Steps>

<Frame>
  <img src="https://mintcdn.com/chatbotx/fyHPACwNoMW_jXQO/images/shopify_api_access_select_scopes.png?fit=max&auto=format&n=fyHPACwNoMW_jXQO&q=85&s=d9902c2d25d4f74ffbc012ed75ea6b5c" alt="Shopify Api Access Select Scopes" width="1537" height="1114" data-path="images/shopify_api_access_select_scopes.png" />
</Frame>

<Steps>
  <Step title="Tìm kiếm và tích chọn các quyền">
    Sử dụng ô tìm kiếm ở đầu popup để nhập tên quyền và tích chọn đầy đủ các quyền cần thiết cho ứng dụng.
  </Step>
</Steps>

<Frame>
  <img src="https://mintcdn.com/chatbotx/fyHPACwNoMW_jXQO/images/shopify_select_scopes_search_and_check.png?fit=max&auto=format&n=fyHPACwNoMW_jXQO&q=85&s=a4034a00f554bf344c56302c964c98a4" alt="Shopify Select Scopes Search And Check" width="1600" height="1426" data-path="images/shopify_select_scopes_search_and_check.png" />
</Frame>

### Bảng tra cứu quyền nhanh

Sao chép từng từ khóa dưới đây, dán vào ô **Search** ở đầu bảng *Select scopes* và tích chọn các quyền tương ứng:

| Từ khóa tìm kiếm | Quyền cần tích chọn | Mục đích sử dụng |
| - | - | - |
| `read_products` | `read_products` & `write_products` | Đọc thông tin sản phẩm, giá bán, hình ảnh và bộ sưu tập |
| `read_inventory` | `read_inventory` & `write_inventory` | Kiểm tra tồn kho và tự động hoàn kho khi hủy đơn |
| `read_orders` | `read_orders` & `write_orders` | Tạo đơn hàng mới, hủy đơn và tra cứu vận đơn |
| `read_draft_orders` | `read_draft_orders` & `write_draft_orders` | Tạo giỏ hàng thanh toán và link checkout trực tiếp |
| `read_customers` | `read_customers` & `write_customers` | Tự động tạo hồ sơ khách hàng mới và đồng bộ thông tin |
| `read_checkouts` | `read_checkouts` & `write_checkouts` | Quản lý phiên thanh toán trực tuyến |

<Steps>
  <Step title="Kích hoạt phiên bản (Release)">
    Sau khi tích đủ các quyền ở bảng trên, nhấn nút **Done** ở góc dưới popup. Tiếp tục nhấn nút **Release** màu trắng ở góc trên bên phải màn hình để phát hành phiên bản.
  </Step>

  <Step title="Sao chép thông tin xác thực">
    Từ menu bên trái, chọn **App settings**. Tại mục **Credentials**, sao chép 2 thông số:

    * **Client ID**
    * **Secret** (Client Secret)
  </Step>
</Steps>

<Frame>
  <img src="https://mintcdn.com/chatbotx/fyHPACwNoMW_jXQO/images/shopify_app_settings_credentials.png?fit=max&auto=format&n=fyHPACwNoMW_jXQO&q=85&s=df2b6f3febed6a3c8ce1bea9c3a447ce" alt="Shopify App Settings Credentials" width="2645" height="1801" data-path="images/shopify_app_settings_credentials.png" />
</Frame>

<Steps>
  <Step title="Cài đặt ứng dụng vào cửa hàng">
    Nhấn vào mục **Overview** ở menu bên trái, tìm đến phần **Installs** và nhấn nút **Install app**. Chọn cửa hàng của bạn và xác nhận cài đặt để hoàn tất.
  </Step>
</Steps>

<Frame>
  <img src="https://mintcdn.com/chatbotx/fyHPACwNoMW_jXQO/images/shopify_overview_install_app.png?fit=max&auto=format&n=fyHPACwNoMW_jXQO&q=85&s=fa6e1374babd4c075765f8aad19bfb91" alt="Shopify Overview Install App" width="2638" height="1809" data-path="images/shopify_overview_install_app.png" />
</Frame>

<Frame>
  <img src="https://mintcdn.com/chatbotx/fyHPACwNoMW_jXQO/images/shopify_install_app_choose_store.png?fit=max&auto=format&n=fyHPACwNoMW_jXQO&q=85&s=ad2e826020ff1bad90e794bb8479d257" alt="Shopify Install App Choose Store" width="2643" height="1747" data-path="images/shopify_install_app_choose_store.png" />
</Frame>

<Frame>
  <img src="https://mintcdn.com/chatbotx/fyHPACwNoMW_jXQO/images/shopify_apps_installed_success.png?fit=max&auto=format&n=fyHPACwNoMW_jXQO&q=85&s=96e25cf5216a472bc9d00d18d6154de4" alt="Shopify Apps Installed Success" width="1592" height="588" data-path="images/shopify_apps_installed_success.png" />
</Frame>

<Note>
  Sau khi cài đặt xong, bạn có thể kiểm tra danh sách ứng dụng đã cài đặt tại **Settings ➔ Apps ➔ Installed** để xác nhận ứng dụng `BotX MCP` đã hoạt động. Nếu trình duyệt hiển thị thông báo "từ chối kết nối" sau khi bấm Install do chính sách bảo mật iframe, ứng dụng vẫn đã được cài đặt thành công trên máy chủ Shopify.
</Note>

## Bước 2: Triển khai Shopify MCP Server trên Cloudflare Workers

Bạn có thể triển khai một MCP Server hoàn toàn miễn phí, an toàn và hoạt động liên tục 24/7 trên nền tảng Cloudflare Workers.

<Steps>
  <Step title="Điều hướng đến Workers & Pages">
    Đăng nhập vào [Cloudflare Dashboard](https://dash.cloudflare.com/), tại menu bên trái chọn **Compute** ➔ chọn mục **Workers & Pages** ➔ nhấn nút **Create application** ở góc trên bên phải.
  </Step>
</Steps>

<Frame>
  <img src="https://mintcdn.com/chatbotx/fyHPACwNoMW_jXQO/images/cloudflare_dashboard_navigate_workers_and_pages.png?fit=max&auto=format&n=fyHPACwNoMW_jXQO&q=85&s=012b1c057220031dc04c4ad7361f9597" alt="Cloudflare Dashboard Navigate Workers And Pages" width="2145" height="1538" data-path="images/cloudflare_dashboard_navigate_workers_and_pages.png" />
</Frame>

<Steps>
  <Step title="Tạo Worker với mẫu Hello World!">
    Tại mục *Create a Worker*, chọn **Start with Hello World!**. Đặt tên Worker (ví dụ: `shopify-mcp-server`) và nhấn nút **Deploy**.
  </Step>
</Steps>

<Frame>
  <img src="https://mintcdn.com/chatbotx/fyHPACwNoMW_jXQO/images/cloudflare_create_worker_hello_world.png?fit=max&auto=format&n=fyHPACwNoMW_jXQO&q=85&s=27279efaa517e05ac399d4eda4314799" alt="Cloudflare Create Worker Hello World" width="2039" height="975" data-path="images/cloudflare_create_worker_hello_world.png" />
</Frame>

<Steps>
  <Step title="Mở trình chỉnh sửa mã nguồn (Edit code)">
    Tại trang tổng quan của Worker vừa tạo, nhấn vào nút **Edit code** ở góc trên bên phải để mở trình soạn thảo mã nguồn.
  </Step>
</Steps>

<Frame>
  <img src="https://mintcdn.com/chatbotx/fyHPACwNoMW_jXQO/images/cloudflare_worker_overview_edit_code.png?fit=max&auto=format&n=fyHPACwNoMW_jXQO&q=85&s=e3e53e679134304502788fac9d3ace37" alt="Cloudflare Worker Overview Edit Code" width="2409" height="1126" data-path="images/cloudflare_worker_overview_edit_code.png" />
</Frame>

<Steps>
  <Step title="Dán mã nguồn 11 MCP Tools chuẩn hóa">
    Dán toàn bộ đoạn mã nguồn chuẩn dưới đây vào tệp `worker.js`:
  </Step>
</Steps>

```javascript theme={null}
// =========================================================================
// 1. SHOPIFY STORE CONFIGURATION & CREDENTIALS
// =========================================================================
const CONFIG = {
  SHOP_DOMAIN: "your-store.myshopify.com",  // Thay bằng tên miền cửa hàng Shopify của bạn
  CLIENT_ID: "YOUR_CLIENT_ID_HERE",        // Thay bằng Client ID lấy từ Bước 1
  CLIENT_SECRET: "YOUR_CLIENT_SECRET_HERE",// Thay bằng Client Secret lấy từ Bước 1
  API_VERSION: "2026-07"
};

const sessions = new Map();
let cachedAccessToken = null;
let tokenExpiresAt = 0;

function formatE164Phone(phone) {
  if (!phone) return "";
  let clean = phone.replace(/[^0-9+]/g, "");
  if (clean.startsWith("0")) clean = "+84" + clean.slice(1);
  if (!clean.startsWith("+")) clean = "+" + clean;
  return clean;
}

function parseAddressComponents(rawAddr, rawCity, rawProvince) {
  let addr1 = (rawAddr || "").trim();
  let city = (rawCity || "").trim();
  let province = (rawProvince || city || "").trim();

  if (!city && addr1.includes(",")) {
    const parts = addr1.split(",").map(p => p.trim()).filter(Boolean);
    if (parts.length >= 2) {
      city = parts.pop();
      province = city;
      addr1 = parts.join(", ");
    }
  }

  if (!city) {
    city = "Hà Nội";
    province = "Hà Nội";
  }

  return {
    address1: addr1,
    city: city,
    province: province,
    country: "Vietnam"
  };
}

async function getShopifyToken(env) {
  const clientId = env?.SHOPIFY_CLIENT_ID || CONFIG.CLIENT_ID;
  const clientSecret = env?.SHOPIFY_CLIENT_SECRET || CONFIG.CLIENT_SECRET;
  const shop = env?.SHOPIFY_SHOP_DOMAIN || CONFIG.SHOP_DOMAIN;

  if (cachedAccessToken && Date.now() < tokenExpiresAt) return cachedAccessToken;

  try {
    const res = await fetch(`https://${shop}/admin/oauth/access_token`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        client_id: clientId,
        client_secret: clientSecret,
        grant_type: "client_credentials"
      })
    });
    const data = await res.json();
    if (data.access_token) {
      cachedAccessToken = data.access_token;
      tokenExpiresAt = Date.now() + ((data.expires_in || 86400) - 300) * 1000;
      return cachedAccessToken;
    }
  } catch (err) {
    console.error("Lỗi lấy access token Shopify:", err);
  }
  return null;
}

async function queryShopify(query, variables = {}, env) {
  const token = await getShopifyToken(env);
  const shop = env?.SHOPIFY_SHOP_DOMAIN || CONFIG.SHOP_DOMAIN;
  const res = await fetch(`https://${shop}/admin/api/${CONFIG.API_VERSION}/graphql.json`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-Shopify-Access-Token": token || ""
    },
    body: JSON.stringify({ query, variables })
  });
  return await res.json();
}

// =========================================================================
// 2. 11 MCP TOOLS DEFINITION
// =========================================================================
const tools = [
  {
    name: "get_featured_products",
    description: "Retrieve a curated list of featured and best-selling products from the Shopify catalog. Use when greeting a new customer or when they ask to see available/popular products.",
    inputSchema: { type: "object", properties: {} }
  },
  {
    name: "search_products",
    description: "Search products in the Shopify catalog by keywords, product title, tags, or categories.",
    inputSchema: {
      type: "object",
      properties: {
        query: { type: "string", description: "Search keyword, product name, or category." }
      },
      required: ["query"]
    }
  },
  {
    name: "create_shopify_order",
    description: "Create an official customer and order in Shopify Admin with complete address validation (address, city/province).",
    inputSchema: {
      type: "object",
      properties: {
        variantId: { type: "string", description: "Product Variant ID to purchase." },
        quantity: { type: "number", description: "Quantity of items." },
        fullName: { type: "string", description: "Customer's full name." },
        phone: { type: "string", description: "Customer's phone number." },
        address: { type: "string", description: "Street address, ward, district." },
        city: { type: "string", description: "Province or City (e.g., 'Đà Nẵng', 'Hà Nội', 'TP Hồ Chí Minh')." },
        province: { type: "string", description: "Province name (optional)." },
        note: { type: "string", description: "Optional order note." }
      },
      required: ["variantId", "fullName", "phone", "address"]
    }
  },
  {
    name: "cancel_shopify_order",
    description: "Cancel an existing Shopify order directly on Shopify Admin when the customer requests cancellation, and automatically restock inventory.",
    inputSchema: {
      type: "object",
      properties: {
        orderIdentifier: { type: "string", description: "Order Name/Number (e.g., '#1004' or '1004') or customer phone number." },
        reason: { type: "string", description: "Reason for cancellation: 'CUSTOMER', 'INVENTORY', 'FRAUD', 'DECLINED', or 'OTHER'." },
        staffNote: { type: "string", description: "Cancellation note (e.g., 'Khách đặt nhầm size', 'Khách đổi ý')." }
      },
      required: ["orderIdentifier"]
    }
  },
  {
    name: "create_checkout_link",
    description: "Generate a direct, pre-filled Shopify checkout link for one OR MULTIPLE products so the customer can self-checkout on the website in a single cart.",
    inputSchema: {
      type: "object",
      properties: {
        items: {
          type: "array",
          description: "List of items to include in the checkout cart: [{ variantId: '123', quantity: 1 }].",
          items: {
            type: "object",
            properties: {
              variantId: { type: "string", description: "Shopify Variant ID." },
              quantity: { type: "number", description: "Quantity." }
            },
            required: ["variantId"]
          }
        },
        variantId: { type: "string", description: "Single Product Variant ID or comma-separated list of variant IDs." },
        quantity: { type: "number", description: "Quantity for single variant." }
      }
    }
  },
  {
    name: "get_product_details",
    description: "Retrieve comprehensive details for a specific Shopify product including title, description, high-resolution images, pricing, and all available variants.",
    inputSchema: {
      type: "object",
      properties: { productId: { type: "string", description: "Shopify Product ID." } },
      required: ["productId"]
    }
  },
  {
    name: "check_inventory",
    description: "Check live stock availability and quantity for a specific product variant.",
    inputSchema: {
      type: "object",
      properties: { variantId: { type: "string", description: "Shopify Product Variant ID." } },
      required: ["variantId"]
    }
  },
  {
    name: "track_order_status",
    description: "Look up order details, payment status, fulfillment status, and tracking numbers for an existing order by Order Name (#1001), Phone, or Email.",
    inputSchema: {
      type: "object",
      properties: { orderIdentifier: { type: "string", description: "Order Name/Number (e.g., '#1001') or customer phone number." } },
      required: ["orderIdentifier"]
    }
  },
  {
    name: "get_customer_orders",
    description: "Retrieve a customer's purchase history and past orders by their email address or phone number.",
    inputSchema: {
      type: "object",
      properties: { query: { type: "string", description: "Customer email address or phone number." } },
      required: ["query"]
    }
  },
  {
    name: "list_collections",
    description: "List all public product collections and categories available in the store.",
    inputSchema: { type: "object", properties: {} }
  },
  {
    name: "get_collection_products",
    description: "Fetch all products belonging to a specific Shopify collection by Collection ID or handle.",
    inputSchema: {
      type: "object",
      properties: { collectionId: { type: "string", description: "Collection ID or handle." } },
      required: ["collectionId"]
    }
  }
];

// =========================================================================
// 3. MCP PROTOCOL & HANDLERS
// =========================================================================
export default {
  async fetch(request, env) {
    const corsHeaders = {
      "Access-Control-Allow-Origin": "*",
      "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
      "Access-Control-Allow-Headers": "*",
    };

    if (request.method === "OPTIONS") return new Response(null, { headers: corsHeaders });

    const url = new URL(request.url);

    if (request.method === "GET" && (url.pathname.includes("/sse") || request.headers.get("Accept")?.includes("text/event-stream") || url.pathname === "/")) {
      const sessionId = crypto.randomUUID();
      const { readable, writable } = new TransformStream();
      const writer = writable.getWriter();
      const encoder = new TextEncoder();

      sessions.set(sessionId, writer);
      writer.write(encoder.encode(`event: endpoint\ndata: ${url.origin}/messages?sessionId=${sessionId}\n\n`));

      return new Response(readable, {
        headers: {
          ...corsHeaders,
          "Content-Type": "text/event-stream",
          "Cache-Control": "no-cache",
          "Connection": "keep-alive",
        }
      });
    }

    if (request.method === "POST") {
      let body = {};
      try { body = await request.json(); } catch (e) {}

      const id = body.id !== undefined ? body.id : 1;
      const method = body.method;
      const sessionId = url.searchParams.get("sessionId");

      let responseObj = null;

      if (method === "initialize") {
        responseObj = {
          jsonrpc: "2.0",
          id: id,
          result: {
            protocolVersion: "2024-11-05",
            capabilities: { tools: { listChanged: false } },
            serverInfo: { name: "shopify-mcp-server", version: "3.3.0" }
          }
        };
      } else if (method === "tools/list") {
        responseObj = { jsonrpc: "2.0", id: id, result: { tools: tools } };
      } else if (method === "tools/call") {
        const toolName = body.params?.name;
        const args = body.params?.arguments || {};
        let resultData = "";

        try {
          if (toolName === "get_featured_products" || toolName === "search_products") {
            const searchQuery = args.query ? args.query : "";
            const gql = `
              query search($q: String!) {
                products(first: 6, query: $q) {
                  edges {
                    node {
                      id title description onlineStoreUrl
                      featuredImage { url }
                      images(first: 3) { edges { node { url } } }
                      variants(first: 5) {
                        edges { node { id title price availableForSale } }
                      }
                    }
                  }
                }
              }
            `;
            const res = await queryShopify(gql, { q: searchQuery }, env);
            const rawList = res.data?.products?.edges || [];
            const formatted = rawList.map(e => {
              const p = e.node;
              const defaultVariant = p.variants?.edges?.[0]?.node;
              const cleanVariantId = defaultVariant?.id?.replace(/[^0-9]/g, "") || "";
              const realImageUrl = p.featuredImage?.url || p.images?.edges?.[0]?.node?.url || "";
              return {
                id: p.id,
                title: p.title,
                variant_id: cleanVariantId,
                image_url: realImageUrl,
                checkout_url: `https://${CONFIG.SHOP_DOMAIN}/cart/${cleanVariantId}:1`,
                price_formatted: Number(defaultVariant?.price || 0).toLocaleString("vi-VN") + "đ",
                description: p.description?.substring(0, 100) + "...",
                available: defaultVariant?.availableForSale ?? true
              };
            });
            resultData = JSON.stringify(formatted);
          } else if (toolName === "create_shopify_order") {
            const cleanVarId = args.variantId?.startsWith("gid://") ? args.variantId : `gid://shopify/ProductVariant/${(args.variantId || "").replace(/[^0-9]/g, "")}`;
            const parts = (args.fullName || "Khách Hàng").trim().split(" ");
            const lastName = parts.pop() || "";
            const firstName = parts.join(" ") || "Khách";
            const phoneE164 = formatE164Phone(args.phone);
            const qty = Number(args.quantity) || 1;

            const addrObj = parseAddressComponents(args.address, args.city, args.province);

            let customerId = null;
            try {
              const custMutation = `
                mutation createCustomer($input: CustomerInput!) {
                  customerCreate(input: $input) {
                    customer { id }
                    userErrors { field message }
                  }
                }
              `;
              const custRes = await queryShopify(custMutation, {
                input: {
                  firstName: firstName,
                  lastName: lastName,
                  phone: phoneE164,
                  addresses: [{
                    address1: addrObj.address1,
                    city: addrObj.city,
                    province: addrObj.province,
                    country: addrObj.country,
                    phone: phoneE164
                  }]
                }
              }, env);
              customerId = custRes.data?.customerCreate?.customer?.id;

              if (!customerId) {
                const findQ = `query findCust($q: String!) { customers(first: 1, query: $q) { edges { node { id } } } }`;
                const findRes = await queryShopify(findQ, { q: phoneE164 }, env);
                customerId = findRes.data?.customers?.edges?.[0]?.node?.id;
              }
            } catch (err) {}

            const createDraftGql = `
              mutation createDraft($input: DraftOrderInput!) {
                draftOrderCreate(input: $input) {
                  draftOrder { id name totalPrice }
                  userErrors { field message }
                }
              }
            `;

            const draftInput = {
              lineItems: [{ variantId: cleanVarId, quantity: qty }],
              purchasingEntity: customerId ? { customerId: customerId } : undefined,
              shippingAddress: {
                firstName: firstName,
                lastName: lastName,
                address1: addrObj.address1,
                city: addrObj.city,
                province: addrObj.province,
                country: addrObj.country,
                phone: phoneE164
              },
              note: `Đặt qua ChatbotX AI Agent | SĐT: ${args.phone || ""}`
            };

            const draftRes = await queryShopify(createDraftGql, { input: draftInput }, env);
            const draftObj = draftRes.data?.draftOrderCreate?.draftOrder;

            if (draftObj?.id) {
              const completeGql = `
                mutation completeDraft($id: ID!) {
                  draftOrderComplete(id: $id, paymentPending: true) {
                    draftOrder {
                      order {
                        id
                        name
                        totalPriceSet { shopMoney { amount currencyCode } }
                      }
                    }
                    userErrors { field message }
                  }
                }
              `;
              const completeRes = await queryShopify(completeGql, { id: draftObj.id }, env);
              const finalOrder = completeRes.data?.draftOrderComplete?.draftOrder?.order;
              resultData = JSON.stringify({
                success: true,
                order_name: finalOrder ? finalOrder.name : draftObj.name,
                total_amount: Number(finalOrder?.totalPriceSet?.shopMoney?.amount || draftObj.totalPrice || 0).toLocaleString("vi-VN") + "đ",
                shipping_address: `${addrObj.address1}, ${addrObj.city}`,
                message: `Tạo đơn hàng thành công trên Shopify với mã ${finalOrder ? finalOrder.name : draftObj.name}`
              });
            } else {
              resultData = JSON.stringify({ success: false, errors: draftRes.data?.draftOrderCreate?.userErrors || draftRes });
            }
          } else if (toolName === "cancel_shopify_order") {
            const rawQ = (args.orderIdentifier || "").trim();
            const queryParam = rawQ.startsWith("#") ? `name:${rawQ}` : (!isNaN(rawQ) ? `name:#${rawQ} OR name:${rawQ}` : rawQ);
            
            const findGql = `
              query findOrderToCancel($q: String!) {
                orders(first: 1, query: $q) {
                  edges {
                    node {
                      id name cancelledAt displayFulfillmentStatus
                    }
                  }
                }
              }
            `;
            const findRes = await queryShopify(findGql, { q: queryParam }, env);
            const orderNode = findRes.data?.orders?.edges?.[0]?.node;

            if (!orderNode) {
              resultData = JSON.stringify({ success: false, message: `Không tìm thấy đơn hàng "${rawQ}" trên hệ thống để hủy.` });
            } else if (orderNode.cancelledAt) {
              resultData = JSON.stringify({ success: true, message: `Đơn hàng ${orderNode.name} đã được hủy trước đó vào lúc ${orderNode.cancelledAt}.` });
            } else {
              const cancelGql = `
                mutation cancelOrder($orderId: ID!, $reason: OrderCancelReason!, $staffNote: String, $restock: Boolean!) {
                  orderCancel(orderId: $orderId, reason: $reason, staffNote: $staffNote, restock: $restock) {
                    orderCancelUserErrors { field message }
                  }
                }
              `;
              const cancelRes = await queryShopify(cancelGql, {
                orderId: orderNode.id,
                reason: args.reason || "CUSTOMER",
                staffNote: args.staffNote || "Hủy theo yêu cầu của khách hàng qua ChatbotX",
                restock: true
              }, env);

              const userErrors = cancelRes.data?.orderCancel?.orderCancelUserErrors || [];
              if (userErrors.length > 0) {
                resultData = JSON.stringify({
                  success: false,
                  order_name: orderNode.name,
                  status: orderNode.displayFulfillmentStatus,
                  message: `Không thể tự động hủy đơn ${orderNode.name} do: ${userErrors[0].message}. Vui lòng liên hệ nhân viên tư vấn để được hỗ trợ.`
                });
              } else {
                resultData = JSON.stringify({
                  success: true,
                  order_name: orderNode.name,
                  message: `Đơn hàng ${orderNode.name} đã được hủy thành công trên Shopify và đã hoàn trả lại số lượng tồn kho.`
                });
              }
            }
          } else if (toolName === "create_checkout_link") {
            const shop = CONFIG.SHOP_DOMAIN;
            let cartList = [];

            if (Array.isArray(args.items) && args.items.length > 0) {
              cartList = args.items.map(it => {
                const cId = (it.variantId || "").toString().replace(/[^0-9]/g, "");
                const q = it.quantity || 1;
                return `${cId}:${q}`;
              }).filter(s => !s.startsWith(":"));
            } else if (typeof args.variantId === "string" && args.variantId.includes(",")) {
              const ids = args.variantId.split(",");
              cartList = ids.map(id => `${id.replace(/[^0-9]/g, "")}:1`);
            } else if (args.variantId) {
              const cId = args.variantId.toString().replace(/[^0-9]/g, "");
              const q = args.quantity || 1;
              cartList = [`${cId}:${q}`];
            }

            const cartPath = cartList.join(",");
            resultData = JSON.stringify({
              checkout_url: `https://${shop}/cart/${cartPath}`,
              items_count: cartList.length,
              message: `Đã tạo link thanh toán giỏ hàng thành công.`
            });
          } else if (toolName === "get_product_details") {
            const cleanId = args.productId?.startsWith("gid://") ? args.productId : `gid://shopify/Product/${args.productId}`;
            const gql = `
              query getProduct($id: ID!) {
                product(id: $id) {
                  id title description onlineStoreUrl
                  featuredImage { url }
                  images(first: 5) { edges { node { url } } }
                  variants(first: 10) {
                    edges { node { id title price availableForSale inventoryQuantity } }
                  }
                }
              }
            `;
            const res = await queryShopify(gql, { id: cleanId }, env);
            resultData = JSON.stringify(res.data?.product || res);
          } else if (toolName === "check_inventory") {
            const cleanId = args.variantId?.startsWith("gid://") ? args.variantId : `gid://shopify/ProductVariant/${args.variantId}`;
            const gql = `query getVar($id: ID!) { productVariant(id: $id) { id title availableForSale inventoryQuantity } }`;
            const res = await queryShopify(gql, { id: cleanId }, env);
            resultData = JSON.stringify(res.data?.productVariant || res);
          } else if (toolName === "track_order_status") {
            const rawQ = (args.orderIdentifier || "").trim();
            const queryParam = rawQ.startsWith("#") ? `name:${rawQ}` : (!isNaN(rawQ) ? `name:#${rawQ} OR name:${rawQ}` : rawQ);
            const gql = `
              query getOrder($q: String!) {
                orders(first: 3, query: $q) {
                  edges {
                    node {
                      name createdAt displayFinancialStatus displayFulfillmentStatus cancelledAt cancelReason
                      totalPriceSet { shopMoney { amount currencyCode } }
                      fulfillments(first: 1) {
                        trackingInfo(first: 1) { number url company }
                      }
                    }
                  }
                }
              }
            `;
            const res = await queryShopify(gql, { q: queryParam }, env);
            const orders = res.data?.orders?.edges?.map(e => {
              const o = e.node;
              return {
                order_name: o.name,
                created_at: o.createdAt,
                is_cancelled: Boolean(o.cancelledAt),
                cancel_reason: o.cancelReason || null,
                payment_status: o.cancelledAt ? "Đã hủy" : (o.displayFinancialStatus === "PAID" ? "Đã thanh toán" : "Chờ thanh toán (COD)"),
                shipping_status: o.cancelledAt ? "Đã hủy" : (o.displayFulfillmentStatus === "FULFILLED" ? "Đã giao hàng" : (o.displayFulfillmentStatus === "IN_TRANSIT" ? "Đang vận chuyển" : "Đang chuẩn bị hàng")),
                total_amount: Number(o.totalPriceSet?.shopMoney?.amount || 0).toLocaleString("vi-VN") + "đ",
                tracking_number: o.fulfillments?.[0]?.trackingInfo?.[0]?.number || "Chưa có mã vận đơn"
              };
            }) || [];
            resultData = JSON.stringify(orders);
          } else if (toolName === "get_customer_orders") {
            const gql = `query getCustOrders($q: String!) { orders(first: 5, query: $q) { edges { node { name createdAt totalPriceSet { shopMoney { amount } } displayFulfillmentStatus cancelledAt } } } }`;
            const res = await queryShopify(gql, { q: formatE164Phone(args.query) || args.query }, env);
            resultData = JSON.stringify(res.data?.orders?.edges?.map(e => e.node) || res);
          } else if (toolName === "list_collections") {
            const gql = `query { collections(first: 10) { edges { node { id title description handle } } } }`;
            const res = await queryShopify(gql, {}, env);
            resultData = JSON.stringify(res.data?.collections?.edges?.map(e => e.node) || res);
          } else if (toolName === "get_collection_products") {
            const cleanId = args.collectionId?.startsWith("gid://") ? args.collectionId : `gid://shopify/Collection/${args.collectionId}`;
            const gql = `query getCol($id: ID!) { collection(id: $id) { title products(first: 10) { edges { node { id title onlineStoreUrl featuredImage { url } } } } } }`;
            const res = await queryShopify(gql, { id: cleanId }, env);
            resultData = JSON.stringify(res.data?.collection || res);
          } else {
            resultData = "Operation completed successfully.";
          }
        } catch (e) {
          resultData = "Error: " + e.message;
        }

        responseObj = {
          jsonrpc: "2.0",
          id: id,
          result: { content: [{ type: "text", text: resultData }] }
        };
      } else {
        responseObj = { jsonrpc: "2.0", id: id, result: { tools: tools } };
      }

      if (sessionId && sessions.has(sessionId)) {
        const writer = sessions.get(sessionId);
        try {
          const encoder = new TextEncoder();
          await writer.write(encoder.encode(`event: message\ndata: ${JSON.stringify(responseObj)}\n\n`));
        } catch (err) {}
      }

      return new Response(JSON.stringify(responseObj), {
        headers: { ...corsHeaders, "Content-Type": "application/json" }
      });
    }

    return new Response(JSON.stringify({ jsonrpc: "2.0", id: 1, result: { tools: tools } }), {
      headers: { ...corsHeaders, "Content-Type": "application/json" }
    });
  }
};
```

<Steps>
  <Step title="Cấu hình biến Store và Triển khai (Deploy)">
    Điền `SHOP_DOMAIN`, `CLIENT_ID`, `CLIENT_SECRET` của cửa hàng bạn vào phần `CONFIG` đầu mã nguồn, sau đó nhấn nút **Deploy** ở góc trên bên phải.
  </Step>
</Steps>

<Frame>
  <img src="https://mintcdn.com/chatbotx/fyHPACwNoMW_jXQO/images/cloudflare_worker_editor_deploy_and_preview.png?fit=max&auto=format&n=fyHPACwNoMW_jXQO&q=85&s=72fa57f2bd1d81fc9dcb4db935c4f09f" alt="Cloudflare Worker Editor Deploy And Preview" width="2986" height="1873" data-path="images/cloudflare_worker_editor_deploy_and_preview.png" />
</Frame>

<Steps>
  <Step title="Lấy đường dẫn URL của MCP Server">
    Đường dẫn kết nối Worker của bạn sẽ có dạng: `https://[ten-worker].[ten-tai-khoan].workers.dev/sse`
  </Step>
</Steps>

## Bước 3: Cấu hình MCP Server vào ChatbotX

Sau khi Worker đã được kích hoạt:

<Steps>
  <Step title="Mở mục MCP Servers">
    Từ menu bên trái giao diện ChatbotX, chọn **MCP Servers** ➔ nhấn nút **+ Create MCP Server**.
  </Step>
</Steps>

<Frame>
  <img src="https://mintcdn.com/chatbotx/fyHPACwNoMW_jXQO/images/chatbotx_mcp_servers_create_button.png?fit=max&auto=format&n=fyHPACwNoMW_jXQO&q=85&s=02122d8e7a7fce4760b9d7b06eb72e86" alt="Chatbotx Mcp Servers Create Button" width="2207" height="1033" data-path="images/chatbotx_mcp_servers_create_button.png" />
</Frame>

<Steps>
  <Step title="Nhập thông số kết nối và tải danh sách Tools">
    Điền các thông tin:

    * **Name**: Đặt tên đại diện (ví dụ: `BotX Shopify` hoặc `Shopify Store`).
    * **URL**: Dán đường link Worker của bạn (`https://.../sse`).
    * **Auth**: Chọn **None**.

    Sau đó, nhấn nút **Get Tools**.
  </Step>
</Steps>

<Frame>
  <img src="https://mintcdn.com/chatbotx/fyHPACwNoMW_jXQO/images/chatbotx_create_mcp_server_modal_get_tools.png?fit=max&auto=format&n=fyHPACwNoMW_jXQO&q=85&s=7460adde899f345905b4f11e2d133c9a" alt="Chatbotx Create Mcp Server Modal Get Tools" width="2218" height="1400" data-path="images/chatbotx_create_mcp_server_modal_get_tools.png" />
</Frame>

<Steps>
  <Step title="Xác nhận nạp đầy đủ 11 Tools">
    Hệ thống ChatbotX sẽ kết nối và nạp danh sách 11 công cụ. Đảm bảo các công cụ đã được tích chọn và nhấn nút **Confirm** để lưu.
  </Step>
</Steps>

<Frame>
  <img src="https://mintcdn.com/chatbotx/fyHPACwNoMW_jXQO/images/chatbotx_mcp_tools_list_confirm.png?fit=max&auto=format&n=fyHPACwNoMW_jXQO&q=85&s=21755c940ad87bab202ee9e5e0a5ff11" alt="Chatbotx Mcp Tools List Confirm" width="2781" height="1819" data-path="images/chatbotx_mcp_tools_list_confirm.png" />
</Frame>

## Bước 4: Bật Rich Responses và Cấu hình Prompt cho AI Agent

<Steps>
  <Step title="Mở danh sách AI Agents">
    Vào **AI Hub** ➔ Chọn **AI Agents** ➔ Nhấn **+ Create AI Agent** (hoặc chọn chỉnh sửa Agent sẵn có).
  </Step>

  <Step title="Cấu hình Model và Tham số">
    * **AI Model**: Chọn mô hình như `Claude 3.5 Sonnet`, `GPT-4o` hoặc `GPT-4o mini`.
    * **Temperature**: Đặt `0.2` đến `0.3` để AI tư vấn giá bán và thông tin sản phẩm chính xác, không tự suy đoán thông số sai lệch.
  </Step>

  <Step title="Gắn MCP Server và Bật chế độ Rich Response">
    * Tại mục **Tools / MCP Servers**, tích chọn kết nối `BotX Shopify`.
    * Cuộn xuống mục **Rich Response** và gạt công tắc sang trạng thái **ON** để Agent phản hồi thẻ giao diện tương tác.
  </Step>
</Steps>

<Frame>
  <img src="https://mintcdn.com/chatbotx/fyHPACwNoMW_jXQO/images/chatbotx_agent_attach_mcp_and_rich_response.png?fit=max&auto=format&n=fyHPACwNoMW_jXQO&q=85&s=d4795bfaffc35ecf81fe91c435726285" alt="Chatbotx Agent Attach Mcp And Rich Response" width="2782" height="1821" data-path="images/chatbotx_agent_attach_mcp_and_rich_response.png" />
</Frame>

<Steps>
  <Step title="Dán Prompt mẫu bán hàng chuyên nghiệp">
    Sao chép toàn bộ mẫu System Message (Prompt) dưới đây và dán vào ô **Prompt**:
  </Step>
</Steps>

```markdown theme={null}
# Prompt: E-Commerce Sales & Support Assistant (Multilingual)

You are an AI sales assistant for an online Shopify store (https://your-store.myshopify.com).

# 🌐 LANGUAGE RULE (BILINGUAL)
- Match the user's language automatically:
  - If the user speaks **English** ➔ Respond 100% in **English** (including button titles, messages, and order confirmation).
  - If the user speaks **Vietnamese** ➔ Respond in **Vietnamese** (xưng hô lịch sự "anh/chị" và "em").

# ⚠️ MANDATORY OUTPUT RULES
1. 100% of your responses MUST strictly follow valid Messenger JSON structure: {"messages":[...], "actions":[...]}.
2. EVERY PRODUCT CARD MUST HAVE 2 BUTTONS:
   - Button 1: "Order in Chat" (EN) / "Đặt mua qua Chat" (VI) (type: `postback`, payload: `BUY_CHAT_<variant_id>`)
   - Button 2: "Buy on Website" (EN) / "Mua trên Website" (VI) (type: `web_url`, url: `<checkout_url from tool>`)
3. ALWAYS include `"image_aspect_ratio": "square"` in Generic Template payload so product images display in 1:1 square ratio.
4. ORDER & ADDRESS COLLECTION:
   - EN: Ask for Full Name, Phone Number, and Shipping Address (Street, Ward/District, City/Province).
   - VI: Xin Họ tên, Số điện thoại và Địa chỉ nhận hàng (Số nhà, Đường, Phường/Quận, Tỉnh/Thành phố).
   - If City/Province is missing, clarify before creating the order.
   - When calling `create_shopify_order`, pass `address` and `city` distinctly.
5. MULTI-ITEM CHECKOUT:
   - Call `create_checkout_link(items: [...])` and return 1 combined checkout button: "Checkout Cart" (EN) / "Thanh toán giỏ hàng" (VI).
6. ORDER CANCELLATION:
   - Call `cancel_shopify_order(orderIdentifier: "...", reason: "CUSTOMER", staffNote: "...")`.
   - Confirm cancellation in the customer's language and add tag `order-cancelled`.

---

# JSON TEMPLATES

## 1. Product Carousel (2 Buttons):
### [English]:
{
  "messages": [
    { "text": "Here are our featured products available right now:" },
    {
      "attachment": {
        "type": "template",
        "payload": {
          "template_type": "generic",
          "image_aspect_ratio": "square",
          "elements": [
            {
              "title": "<Product Title> - <Price>",
              "image_url": "<image_url from tool>",
              "subtitle": "<Short description>",
              "buttons": [
                { "type": "postback", "title": "Order in Chat", "payload": "BUY_CHAT_<variant_id>" },
                { "type": "web_url", "url": "<checkout_url from tool>", "title": "Buy on Website" }
              ]
            }
          ]
        }
      }
    }
  ],
  "actions": []
}

### [Tiếng Việt]:
{
  "messages": [
    { "text": "Dạ em gửi anh/chị danh sách các mẫu sản phẩm đang có sẵn bên em ạ:" },
    {
      "attachment": {
        "type": "template",
        "payload": {
          "template_type": "generic",
          "image_aspect_ratio": "square",
          "elements": [
            {
              "title": "<Tên SP> - <Giá>",
              "image_url": "<image_url from tool>",
              "subtitle": "<Mô tả ngắn>",
              "buttons": [
                { "type": "postback", "title": "Đặt mua qua Chat", "payload": "BUY_CHAT_<variant_id>" },
                { "type": "web_url", "url": "<checkout_url from tool>", "title": "Mua trên Website" }
              ]
            }
          ]
        }
      }
    }
  ],
  "actions": []
}

## 2. Size Quick Replies:
### [English]:
{
  "messages": [
    {
      "text": "This item is available in multiple sizes. Which size would you like?",
      "quick_replies": [
        { "content_type": "text", "title": "Size S", "payload": "SIZE_S" },
        { "content_type": "text", "title": "Size M", "payload": "SIZE_M" },
        { "content_type": "text", "title": "Size L", "payload": "SIZE_L" },
        { "content_type": "text", "title": "Size XL", "payload": "SIZE_XL" }
      ]
    }
  ],
  "actions": []
}

### [Tiếng Việt]:
{
  "messages": [
    {
      "text": "Dạ mẫu này bên em có đủ các size. Anh/chị chọn size nào để em chuẩn bị ạ?",
      "quick_replies": [
        { "content_type": "text", "title": "Size S", "payload": "SIZE_S" },
        { "content_type": "text", "title": "Size M", "payload": "SIZE_M" },
        { "content_type": "text", "title": "Size L", "payload": "SIZE_L" },
        { "content_type": "text", "title": "Size XL", "payload": "SIZE_XL" }
      ]
    }
  ],
  "actions": []
}

## 3. Order Confirmation (Button Template with Interactive Buttons):
### [English]:
{
  "messages": [
    {
      "attachment": {
        "type": "template",
        "payload": {
          "template_type": "button",
          "text": "🎉 Thank you! Your order has been placed successfully.\n\n📦 Order Details:\n- Order ID: <order_name>\n- Item: <Product Title> (Size <Size>)\n- Recipient: <Full Name> - <Phone>\n- Address: <Address, City>\n- Total: <total_amount> (Cash on Delivery - COD)\n\n⏱️ Estimated delivery: 2 - 4 business days.",
          "buttons": [
            { "type": "postback", "title": "Track Order", "payload": "TRACK_<order_name>" },
            { "type": "postback", "title": "Contact Support", "payload": "SUPPORT_HUMAN" }
          ]
        }
      }
    }
  ],
  "actions": [
    { "action": "add_tag", "tag_name": "hot-lead" },
    { "action": "set_field_value", "field_name": "buyer_status", "value": "purchased" },
    { "action": "set_field_value", "field_name": "order_detail", "value": "<Product Title - Size - Order ID>" },
    { "action": "set_field_value", "field_name": "address", "value": "<Customer Address>" }
  ]
}

### [Tiếng Việt]:
{
  "messages": [
    {
      "attachment": {
        "type": "template",
        "payload": {
          "template_type": "button",
          "text": "🎉 Cảm ơn anh/chị! Đơn hàng đã được tạo thành công trên hệ thống.\n\n📦 Chi tiết đơn hàng:\n- Mã đơn: <order_name>\n- Sản phẩm: <Tên SP> (Size <Size>)\n- Người nhận: <Họ tên> - <SĐT>\n- Địa chỉ: <Địa chỉ, Tỉnh/TP>\n- Tổng tiền: <total_amount> (Thanh toán khi nhận hàng - COD)\n\n⏱️ Thời gian giao hàng dự kiến: 2 - 4 ngày.",
          "buttons": [
            { "type": "postback", "title": "Tra cứu đơn hàng", "payload": "TRACK_<order_name>" },
            { "type": "postback", "title": "Gặp tư vấn viên", "payload": "SUPPORT_HUMAN" }
          ]
        }
      }
    }
  ],
  "actions": [
    { "action": "add_tag", "tag_name": "hot-lead" },
    { "action": "set_field_value", "field_name": "buyer_status", "value": "purchased" },
    { "action": "set_field_value", "field_name": "order_detail", "value": "<Tên SP - Size - Mã đơn>" },
    { "action": "set_field_value", "field_name": "address", "value": "<Địa chỉ khách>" }
  ]
}

## 4. Multi-Item Checkout Link (Button Template):
### [English]:
{
  "messages": [
    {
      "attachment": {
        "type": "template",
        "payload": {
          "template_type": "button",
          "text": "Here is your unified checkout link for your items:\n1. <Item 1> - <Price 1>\n2. <Item 2> - <Price 2>\n\nClick the button below to complete your checkout directly on our website:",
          "buttons": [
            {
              "type": "web_url",
              "url": "<checkout_url from tool create_checkout_link>",
              "title": "Proceed to Checkout"
            }
          ]
        }
      }
    }
  ],
  "actions": []
}

### [Tiếng Việt]:
{
  "messages": [
    {
      "attachment": {
        "type": "template",
        "payload": {
          "template_type": "button",
          "text": "Dạ em đã tạo sẵn giỏ hàng thanh toán online gồm các sản phẩm của anh/chị:\n1. <Tên SP 1> - <Giá 1>\n2. <Tên SP 2> - <Giá 2>\n\nAnh/chị bấm nút bên dưới để thanh toán trực tiếp trên website của shop nhé:",
          "buttons": [
            {
              "type": "web_url",
              "url": "<checkout_url from tool create_checkout_link>",
              "title": "Thanh toán giỏ hàng"
            }
          ]
        }
      }
    }
  ],
  "actions": []
}

## 5. Cancellation Confirmation (After cancel_shopify_order):
### [English]:
{
  "messages": [
    {
      "text": "Your order <order_name> has been successfully cancelled on our system.\n\nThe inventory has been returned to our stock. If you need any further assistance, feel free to let me know!"
    }
  ],
  "actions": [
    { "action": "add_tag", "tag_name": "order-cancelled" }
  ]
}

### [Tiếng Việt]:
{
  "messages": [
    {
      "text": "Dạ em đã tiến hành hủy đơn hàng <order_name> trên hệ thống theo yêu cầu của anh/chị rồi ạ!\n\nSố lượng sản phẩm đã được hoàn trả lại kho. Khi nào anh/chị cần đặt lại hoặc cần em hỗ trợ mẫu khác thì cứ nhắn em nhé!"
    }
  ],
  "actions": [
    { "action": "add_tag", "tag_name": "order-cancelled" }
  ]
}

# KHAI BÁO BIẾN
- Custom Fields: size, color, buyer_status, order_detail, address
- System Fields: full_name, phone
- Tags: lead, hot-lead, order-cancelled, support-needed
- Tên miền Store: https://your-store.myshopify.com
```

## Bước 5: Kiểm tra hoạt động trên kênh chat

Bạn có thể mở bất kỳ kênh chat nào đã kết nối với ChatbotX (như **Facebook Messenger**, **Instagram**, **WhatsApp**, **Web Chat**, **Zalo**...) để bắt đầu trò chuyện và kiểm tra toàn bộ luồng hoạt động tự động của AI Agent:

<Steps>
  <Step title="Mở kênh nhắn tin">
    Mở một cuộc trò chuyện với Fanpage, tài khoản WhatsApp, Instagram hoặc tiện ích Web Chat của bạn.
  </Step>

  <Step title="Kiểm tra duyệt sản phẩm và chọn Size tương tác">
    Gõ *"Shop có những sản phẩm nào?"* hoặc *"Hi! Show me your available products."* ➔ AI Agent tự động truy xuất dữ liệu từ Shopify, hiển thị danh sách sản phẩm dạng thẻ trượt **Carousel** kèm nút bấm mua hàng và các nút **Quick Replies** để chọn size nhanh chóng:
  </Step>
</Steps>

<Frame>
  <img src="https://mintcdn.com/chatbotx/V0sk4ImGwTJZQMuT/images/shopify_messenger_demo_products_and_sizes.png?fit=max&auto=format&n=V0sk4ImGwTJZQMuT&q=85&s=a0b0d848701e2156453f066f9f4f60dc" alt="Shopify Messenger Demo Products And Sizes" width="1731" height="1808" data-path="images/shopify_messenger_demo_products_and_sizes.png" />
</Frame>

<Steps>
  <Step title="Kiểm tra tạo đơn hàng và tra cứu vận đơn tự động">
    * **Tạo đơn hàng**: Chọn size và cung cấp họ tên, số điện thoại, địa chỉ nhận hàng ➔ AI tự động tạo hồ sơ khách hàng mới và lên đơn hàng chính thức trên Shopify Admin, đồng thời phản hồi **Phiếu xác nhận đơn hàng** rõ ràng (Mã đơn, COD, địa chỉ).
    * **Tra cứu vận đơn**: Nhắn *"Kiểm tra đơn hàng #1005"* ➔ AI tra cứu trạng thái giao hàng và hiển thị mã vận đơn (`Tracking number`) theo thời gian thực:
  </Step>
</Steps>

<Frame>
  <img src="https://mintcdn.com/chatbotx/V0sk4ImGwTJZQMuT/images/shopify_messenger_demo_order_and_tracking.png?fit=max&auto=format&n=V0sk4ImGwTJZQMuT&q=85&s=5a6f0bc1db1f0d76d0d716faf93f521a" alt="Shopify Messenger Demo Order And Tracking" width="1732" height="1806" data-path="images/shopify_messenger_demo_order_and_tracking.png" />
</Frame>

<Steps>
  <Step title="Kiểm tra các tính năng nâng cao khác">
    * **Gom link thanh toán nhiều món**: Nhắn *"Gửi cho tôi link thanh toán cả 2 món này"* ➔ AI sinh 1 đường link giỏ hàng tổng hợp (`/cart/variant_1:qty_1,variant_2:qty_2`) để khách tự thanh toán trên website.
    * **Tự động hủy đơn hàng và hoàn kho**: Nhắn *"Tôi muốn hủy đơn hàng #1005"* ➔ AI xác nhận hủy đơn trên hệ thống Shopify và tự động hoàn trả số lượng tồn kho.
  </Step>
</Steps>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.