Tài liệu nhà phát triểnBản Markdownopenapi.jsonllms.txt

Sự kiện

Sự kiện là thứ khởi động một luồng: khối Kích hoạt chọn một loại sự kiện, và mỗi lần sự kiện ấy xảy ra ở shop, luồng chạy với một mục là envelope của sự kiện. DANIX chỉ ghi sự kiện khi shop có luồng đang bật nghe loại ấy (và với tin nhắn, nghe đúng trang ấy) và shop còn dùng được tính năng Tự động hoá.

Envelope

{
  "id": "evt_018f3b8e-…",
  "type": "order.status_changed",
  "apiVersion": "v1",
  "createdAt": "2026-10-01T08:30:00.000Z",
  "shop": { "id": "…", "slug": "ten-shop" },
  "changes": { "fields": ["status"], "status": { "from": "new", "to": "confirmed" } },
  "data": { "id": "…", "code": "…", "status": "confirmed" }
}
Trường Ý nghĩa
id Mã của sự kiện: chuỗi có tiền tố evt_, tối đa 68 ký tự. Cùng một giá trị ở mọi luồng nhận cùng sự kiện. Khác với webhook-id (mã của lượt gửi). Coi nó là chuỗi mờ đục — không phải UUID, đừng lưu vào cột kiểu uuid.
type Loại sự kiện, xem bảng bên dưới.
apiVersion Phiên bản hình dạng dữ liệu, hiện là v1.
createdAt Thời điểm sự kiện xảy ra, ISO 8601 UTC.
shop Shop phát sinh sự kiện: id và slug.
changes Chỉ có ở các sự kiện sửa. Xem bên dưới.
data Nội dung của tài nguyên, cùng hình dạng với phản hồi GET tương ứng trong tham chiếu: bạn đọc data y như đã đọc một bản ghi qua API.

changes

changes cho biết trường nào đã đổi, không chứa giá trị cũ của chúng:

  • fields: danh sách tên trường đã đổi — đúng tên trường của data (camelCase, ví dụ shippingFee; trường của mẫu mã viết variants.price). Đổi liên hệ hay địa chỉ của khách hiện là contacts / addresses, đổi ảnh sản phẩm là images, mốc mới của chặng hoàn (vận đơn giao một phần) là events. Thay đổi ở phần dữ liệu không có trong data không được liệt kê, và lượt sửa chỉ chạm phần ấy (ví dụ đường dẫn rút gọn của sản phẩm, ảnh đại diện của khách, ghi chú in của đơn) không được gửi: DANIX không gửi gì cho bạn, luồng dừng ngay ở khối Kích hoạt (nhật ký của shop vẫn ghi một lượt chạy bị bỏ qua, ẩn mặc định);
  • status: có khi trạng thái đổi, dạng { "from": …, "to": … }. Đây là giá trị duy nhất ngoài tên trường mà changes mang.

Muốn biết giá trị mới của một trường, đọc data. Muốn biết giá trị cũ, bạn tự giữ bản sao ở phía mình.

Danh mục sự kiện

type Khi nào data là Quyền đọc cần có
order.created Đơn hàng được tạo Đơn hàng pos.orders.read
order.updated Một trường trong data của đơn được sửa Đơn hàng pos.orders.read
order.status_changed Đơn đổi trạng thái Đơn hàng pos.orders.read
order.deleted Đơn bị xoá Đơn hàng pos.orders.read
product.created Sản phẩm được tạo Sản phẩm pos.products.read
product.updated Một trường trong data của sản phẩm được sửa (kể cả mẫu mã, ảnh) Sản phẩm pos.products.read
product.deleted Sản phẩm bị xoá Sản phẩm pos.products.read
inventory.stock_changed Tồn kho của một mẫu mã đổi Dòng tồn kho pos.inventory.read và pos.products.read
customer.created Khách hàng được tạo Khách hàng pos.customers.read
customer.updated Một trường trong data của khách được sửa (kể cả liên hệ, địa chỉ) Khách hàng pos.customers.read
customer.deleted Khách hàng bị xoá Khách hàng pos.customers.read
shipment.created Vận đơn được tạo Vận đơn pos.shipping.read và pos.orders.read
shipment.status_changed Vận đơn đổi status, hoặc chặng hoàn của đơn giao một phần sang bước mới Vận đơn pos.shipping.read và pos.orders.read
message.received Khách nhắn tin tới một trang chat Tin nhắn social.pages.read và social.conversations.read
message.sent Shop gửi tin tới khách Tin nhắn social.pages.read và social.conversations.read

Luồng chạy dưới một tài khoản riêng của chính nó; chỉ gửi đi dữ liệu mà tài khoản ấy đọc được theo cột "Quyền đọc cần có", và với tin nhắn chỉ trên các trang đã chọn cho luồng. Người chỉ có quyền xem luồng không đọc được nội dung gửi của loại dữ liệu mà họ không có quyền đọc.

Ví dụ từng loại

Các ví dụ dưới đây rút gọn data thành id kèm vài trường; data thật đầy đủ như phản hồi GET tương ứng. Nút Chạy thử trong ứng dụng Tự động hoá gửi envelope mẫu đầy đủ của từng loại tới khối của bạn.

Đơn hàng

{ "id": "evt_018f3b8e-…", "type": "order.created", "apiVersion": "v1", "createdAt": "2026-10-01T08:30:00.000Z",
  "shop": { "id": "…", "slug": "ten-shop" },
  "data": { "id": "…", "code": "DH0001", "status": "new" } }
{ "id": "evt_018f3b8e-…", "type": "order.updated", "apiVersion": "v1", "createdAt": "2026-10-01T08:35:00.000Z",
  "shop": { "id": "…", "slug": "ten-shop" },
  "changes": { "fields": ["note", "shippingFee"] },
  "data": { "id": "…", "code": "DH0001", "status": "new" } }
{ "id": "evt_018f3b8e-…", "type": "order.status_changed", "apiVersion": "v1", "createdAt": "2026-10-01T09:00:00.000Z",
  "shop": { "id": "…", "slug": "ten-shop" },
  "changes": { "fields": ["status"], "status": { "from": "new", "to": "confirmed" } },
  "data": { "id": "…", "code": "DH0001", "status": "confirmed" } }

order.deleted có cùng hình dạng, data là bản ghi đơn đã bị xoá: status là deleted và có deletedAt. product.deleted và customer.deleted cũng mang deletedAt.

Sản phẩm, khách hàng

product.created, product.updated, product.deleted và customer.created, customer.updated, customer.deleted cùng dạng envelope với đơn hàng: data là sản phẩm hay khách hàng; các sự kiện updated mang changes.fields.

{ "id": "evt_018f3b8e-…", "type": "customer.updated", "apiVersion": "v1", "createdAt": "2026-10-01T10:00:00.000Z",
  "shop": { "id": "…", "slug": "ten-shop" },
  "changes": { "fields": ["contacts"] },
  "data": { "id": "…" } }

Tồn kho

{ "id": "evt_018f3b8e-…", "type": "inventory.stock_changed", "apiVersion": "v1", "createdAt": "2026-10-01T11:00:00.000Z",
  "shop": { "id": "…", "slug": "ten-shop" },
  "changes": { "fields": ["quantity"] },
  "data": { "…": "dòng tồn kho của một mẫu mã tại một kho" } }

Vận đơn

{ "id": "evt_018f3b8e-…", "type": "shipment.status_changed", "apiVersion": "v1", "createdAt": "2026-10-01T12:00:00.000Z",
  "shop": { "id": "…", "slug": "ten-shop" },
  "changes": { "fields": ["status"], "status": { "from": "…", "to": "…" } },
  "data": { "id": "…" } }

shipment.created cùng dạng, không có changes.

Đơn giao một phần: chặng đi kết thúc ở partially_returned (trạng thái cuối, không đổi nữa), rồi phần hàng hoàn về theo một mã riêng của hãng trên cùng vận đơn. Mỗi bước của chặng hoàn phát một shipment.status_changed không có changes.status (vì status đứng yên), changes.fields là ["events"], và mốc mới nằm trong data.events:

{ "id": "evt_018f3b8e-…", "type": "shipment.status_changed", "apiVersion": "v1", "createdAt": "2026-10-03T09:00:00.000Z",
  "shop": { "id": "…", "slug": "ten-shop" },
  "changes": { "fields": ["events"] },
  "data": { "id": "…", "status": "partially_returned", "events": ["…"] } }

Tin nhắn

{ "id": "evt_018f3b8e-…", "type": "message.received", "apiVersion": "v1", "createdAt": "2026-10-01T13:00:00.000Z",
  "shop": { "id": "…", "slug": "ten-shop" },
  "data": { "id": "…" } }

message.sent cùng dạng. Khi khối Kích hoạt chọn một trong hai sự kiện tin nhắn, bạn phải chọn trang chat mà luồng lắng nghe.

Ghi chú cho bên nhận

  • Danh mục sự kiện và trường trong data có thể được bổ sung mà không đổi phiên bản: bỏ qua loại sự kiện và trường lạ.
  • Sự kiện giao theo kiểu ít nhất một lần và không đảm bảo thứ tự: khử trùng theo webhook-id (hoặc theo id của sự kiện nếu bạn nhận ở nhiều luồng), và dùng createdAt của envelope để biết sự kiện nào mới hơn — không phải mọi data đều có updatedAt (sản phẩm, chi tiết vận đơn và dòng tồn không có). Xem Luồng tự động và webhook.
  • Tạo mới chỉ phát *.created: tạo đơn không kèm order.status_changed, và liên hệ, địa chỉ, mẫu mã, ảnh tạo cùng lúc với khách hay sản phẩm không kèm *.updated.
  • Đơn "trả để đổi" (data.exchangeReturn là true) là đơn khách gửi hàng về để ĐỔI, không phải để hoàn tiền. Lượt duyệt hoàn đổi mục đích của đơn (hoàn ↔ đổi) gửi order.updated với changes.fields chứa exchangeReturn, kể cả khi trạng thái và tiền không đổi.
  • *.updated chỉ được gửi khi có ít nhất một trường của data đổi, nên luôn mang changes; sửa phần dữ liệu không có trong data không gửi gì. shipment.status_changed được gửi khi status đổi (mang changes.status) và khi chặng hoàn của đơn giao một phần sang bước mới (changes.fields là ["events"], không có changes.status). Mốc hành trình khác không đổi status không phát sự kiện; đọc chúng ở data.events khi gọi GET.
  • Webhook là đường thời gian thực; updatedSince là đường đối soát bù những gì bạn có thể đã lỡ.