OpsOne AI · Sapo & Shopee
Tích hợp · Đa kênh

Hướng dẫn tích hợp Sapo & Shopee với OpsOne AI

Khi anh/chị bán hàng đa kênh (cửa hàng Sapo, Shopee, Zalo, web), việc nhập tay từng đơn vào OpsOne AI rất tốn thời gian và dễ sai. Tài liệu này hướng dẫn anh/chị thiết lập tích hợp 2 chiều để OpsOne AI tự động kéo đơn từ Sapo về, đẩy trạng thái thanh toán ngược lại, và đồng bộ tồn kho — chỉ cấu hình 1 lần, chạy mãi.

1. Tại sao phải tích hợp?

Nếu anh/chị đang dùng Sapo POS hoặc Sapo Omnichannel (cửa hàng + Shopee + Lazada + TikTok Shop), thì Sapo là nơi nhận đơn. Còn OpsOne AI là nơi anh/chị quản trị tổng thể: công nợ, dòng tiền, kế toán, kho, báo cáo lãi lỗ. Hai hệ phải kết nối, nếu không sẽ xảy ra 3 vấn đề:

Tích hợp Sapo + OpsOne giải quyết cả ba: đơn tự sync về OpsOne theo nhịp anh/chị đặt (TBBV đang để 15 phút), thanh toán đẩy ngược lên Sapo, tồn kho cập nhật 2 chiều.

1
🛒
Khách đặt trên Sapo / Shopee
2
🔄
Scheduler Pull mỗi 5'
3
📦
Đơn vào OpsOne (sapo_id)
4
💰
Thu tiền → Push lên Sapo
5
📊
Báo cáo + Tồn kho tự cập nhật
Lưu ý phạm vi: OpsOne AI tích hợp Sapo trực tiếp qua API. Còn Shopee, Lazada, TikTok Shop sẽ đi qua Sapo Omnichannel trước, rồi từ Sapo đẩy về OpsOne. Tích hợp Shopee trực tiếp (không qua Sapo) đang trong roadmap — xem mục 7.

2. Thuật ngữ cần nhớ

API Key / Access TokenCREDENTIALS
Chìa khóa để OpsOne AI gọi vào hệ thống Sapo của anh/chị. Anh/chị lấy 2 mã này từ trang admin Sapo, dán vào Cài đặt project trong OpsOne. Không chia sẻ cho ai khác — ai có 2 mã này đều thao tác được trên cửa hàng Sapo.
Ví dụ: sapo_api_key = abc123…, sapo_token = xyz789…
WebhookREAL-TIME
Cơ chế Sapo "gọi điện" báo OpsOne mỗi khi có đơn mới hoặc đơn thay đổi. Khác Scheduler (chạy theo phút), Webhook gần như tức thời (1-3 giây). Cần cấu hình URL phía Sapo trỏ về https://app.opsoneai.com/api/sapo-webhook/...
SchedulerCRON
Tiến trình chạy ngầm trong OpsOne, cứ tới nhịp đã đặt cho dự án (ô sapo_sync_interval, tính bằng phút) lại kéo đơn mới từ Sapo về. Đây là "lưới an toàn" — kể cả khi Webhook bị lỗi, Scheduler vẫn đảm bảo đơn được sync trong tối đa một nhịp.
PullSAPO → OPSONE
Hành động kéo dữ liệu từ Sapo về OpsOne (đơn hàng, khách hàng, sản phẩm). Pull là 1 chiều: OpsOne hỏi xin Sapo, không đụng vào dữ liệu Sapo.
PushOPSONE → SAPO
Hành động đẩy dữ liệu từ OpsOne lên Sapo. Hiện đang dùng cho 1 thứ quan trọng: phiếu nhận tiền của OpsOne được approve sẽ tự đẩy lên Sapo thành transaction (Sapo biết đơn đã thu tiền).
Sapo OrderORDER
Đơn hàng tạo ra trong Sapo (POS, web Sapo, hoặc từ Shopee/Lazada sync về Sapo). Sau khi Pull về OpsOne, đơn này có thêm cột sapo_id để biết nó nguồn gốc từ Sapo.
Sapo IDMAPPING KEY
Mã định danh đơn trong hệ thống Sapo. OpsOne dùng sapo_id để map 1-1 giữa 2 hệ: đơn nào đã sync rồi sẽ không bị Pull trùng lần thứ 2.
Ví dụ: đơn Sapo số SP12345 có sapo_id = 987654321 trong DB OpsOne.
Marketplace ChannelCHANNEL
Kênh sàn TMĐT: shopee, lazada, tiktok. Sapo Omnichannel sẽ gắn nhãn này lên đơn để anh/chị biết đơn về từ kênh nào.

3. Tích hợp Sapo từng bước

3.1. Lấy API key + Access Token từ Sapo admin

  1. Đăng nhập trang admin Sapo của anh/chị (vd https://abc.mysapo.vn/admin).
  2. Vào menu Cấu hình → Thiết lập cửa hàng → API (hoặc Quản lý ứng dụng tuỳ phiên bản Sapo).
  3. Bấm Tạo ứng dụng mới → đặt tên (ví dụ "OpsOne AI Integration") → cấp quyền: Đơn hàng (read/write), Khách hàng (read), Sản phẩm (read), Tồn kho (read/write).
  4. Sapo sinh ra 2 mã: API Key và Access Token. Copy cả hai vào nơi an toàn (không gửi qua chat).
  5. Ghi nhớ thêm tên miền cửa hàng (subdomain trước .mysapo.vn) — đây là sapo_store.

3.2. Điền credentials vào OpsOne

  1. Đăng nhập app.opsoneai.com bằng tài khoản admin của project.
  2. Vào Cài đặt (bánh răng góc dưới sidebar) → tab Tích hợp.
  3. Khu vực Sapo, điền 3 trường:
    • sapo_store — tên miền cửa hàng Sapo (vd abc nếu shop là abc.mysapo.vn).
    • sapo_api_key — API Key vừa lấy.
    • sapo_token — Access Token vừa lấy.
  4. Bấm Lưu. OpsOne mã hóa và lưu vào DB, không hiển thị lại token sau khi lưu.

3.3. Bật cờ sapo_enabled

Sau khi điền credentials, anh/chị cần bật cờ sapo_enabled = 1 cho project. Có 2 cách:

Cảnh báo về double-edit: Khi đã bật sync, không nên sửa cùng 1 đơn ở cả Sapo và OpsOne trong khoảng thời gian gần nhau. Ví dụ: Sapo POS đổi số lượng lúc 10:00, OpsOne sửa giá lúc 10:02 → khi Scheduler chạy lúc 10:05 sẽ ghi đè thay đổi của OpsOne bằng dữ liệu Sapo. Quy tắc an toàn: đơn đã vào OpsOne thì sửa trên OpsOne, đừng quay lại Sapo sửa.

3.4. Test kết nối

  1. Vẫn ở tab Tích hợp, bấm nút "Test kết nối".
  2. Nếu trả về OK + số đơn hàng 7 ngày gần nhất → cấu hình đúng.
  3. Nếu trả về 401 Unauthorized → token sai hoặc hết hạn, lấy lại từ Sapo.
  4. Nếu trả về 403 Forbidden → app Sapo chưa cấp đủ quyền (vào lại bước 3.1, mở thêm scope).
  5. Nếu timeout → IP server có thể đang bị Sapo block, liên hệ support OpsOne.

4. Pull đơn từ Sapo

Sau khi bật sapo_enabled, OpsOne tự động chạy Scheduler kéo đơn về theo nhịp sapo_sync_interval. ⚠️ Ô này mặc định 0 = TẮT, nên phải đặt một số phút (TBBV đang để 15) — bật sapo_enabled một mình thì Scheduler chưa kéo gì.

Cơ chế hoạt động

Đồng bộ thủ công (nếu cần kéo gấp)

Nếu anh/chị không muốn chờ tới nhịp kế tiếp (ví dụ vừa có đơn cao điểm cần xử lý ngay):

  1. Vào module CRM → tab Đơn hàng.
  2. Bấm nút "Đồng bộ Sapo ngay" ở góc phải.
  3. Hệ thống chạy Pull ngay lập tức, hiện thông báo "Đã sync X đơn mới" trong 5-30 giây.
Limit: Sapo API có rate limit ~40 request/phút. Nếu anh/chị có hơn 200 đơn/ngày, Scheduler tự chia trang để không vượt limit. Đừng bấm "Đồng bộ ngay" liên tục — sẽ bị 429 Too Many Requests.

5. Push transaction (thanh toán) lên Sapo

Đây là phần "2 chiều" quan trọng nhất. Khi anh/chị thu tiền 1 đơn Sapo trong OpsOne, hệ thống sẽ tự đẩy giao dịch thanh toán đó ngược về Sapo để Sapo cập nhật financial_status = paid.

Điều kiện kích hoạt Push

Luồng Push

1
📝
Tạo phiếu nhận tiền
2
✅
Approve
3
🚀
Push POST /transactions.json
4
🔄
Sapo update financial_status
5
📊
Báo cáo Sapo đúng số
Lợi ích: Nhân viên thu ngân Sapo không cần nhập lại payment. Báo cáo doanh thu trên Sapo khớp 100% với OpsOne. Không còn cảnh "OpsOne ghi đã thu, Sapo vẫn còn nợ".

Push thất bại — xử lý thế nào?

6. Đồng bộ tồn kho

Khi đơn Sapo về OpsOne, hệ thống đồng thời sinh các bản ghi trong bảng stock_transactions để Module Kho biết phải trừ tồn kho bao nhiêu sản phẩm.

Quy tắc sinh stock_transactions

Vì sao dùng sapo_id IS NOT NULL mà không phải source = 'sapo'? Trong quá trình migrate dữ liệu cũ, có một số đơn được tạo bằng tay nhưng vẫn gắn sapo_id (để map về Sapo sau này), và ngược lại đơn Sapo cũ chưa cập nhật cột source. Lọc theo sapo_id IS NOT NULL là nguồn chân lý duy nhất.

Nếu Module Phân tích kho hiển thị số sai

  1. Kiểm tra Scheduler có chạy không: vào Cài đặt → Scheduler status.
  2. Chạy thủ công lệnh re-build stock_transactions từ tab Tích hợp.
  3. Nếu vẫn sai, liên hệ support — có thể cần backfill từ đơn cũ.

7. Tích hợp Shopee (và các sàn khác)

Cách 1 — Qua Sapo Omnichannel (khuyến nghị)

Đây là cách hoạt động ngay hôm nay:

  1. Anh/chị bật Sapo Omnichannel và kết nối shop Shopee/Lazada/TikTok vào Sapo (phía Sapo có hướng dẫn riêng).
  2. Mỗi đơn về từ Shopee sẽ được Sapo nhận vào hệ thống, có nhãn channel = 'shopee'.
  3. OpsOne Pull từ Sapo về như thường lệ — đơn Shopee tự kèm theo nhãn channel để báo cáo phân tích theo kênh.

Cách 2 — Tích hợp Shopee trực tiếp (roadmap)

Một số anh/chị không dùng Sapo Omnichannel, chỉ có shop Shopee độc lập. OpsOne đang phát triển adapter Shopee Partner API riêng (gọi thẳng Shopee, không qua Sapo). Tiến độ:

So sánh nhanh: Nếu anh/chị đã trả phí Sapo Omnichannel, dùng Cách 1 là rẻ + ổn định nhất. Nếu chỉ có Shopee và không muốn trả thêm Sapo, hãy đợi Cách 2.

8. Cấu hình Webhook (real-time, advanced)

Nhịp 15 phút đã đủ cho hầu hết doanh nghiệp. Nhưng nếu anh/chị bán hàng cao điểm (Sale 12.12, Black Friday, livestream), độ trễ một nhịp có thể quá lâu. Lúc đó cấu hình Webhook để Sapo "gọi" OpsOne ngay khi có đơn.

URL endpoint của OpsOne

Sự kiệnURL Webhook
Đơn được tạohttps://app.opsoneai.com/api/sapo-webhook/orders/create
Đơn cập nhậthttps://app.opsoneai.com/api/sapo-webhook/orders/update
Đơn bị hủyhttps://app.opsoneai.com/api/sapo-webhook/orders/cancel
Thanh toán cập nhậthttps://app.opsoneai.com/api/sapo-webhook/transactions/update

Cách cấu hình

  1. Vào admin Sapo → Cấu hình → Thông báo Webhook.
  2. Bấm Tạo Webhook, chọn sự kiện (ví dụ "Đơn hàng được tạo").
  3. Dán URL tương ứng từ bảng trên.
  4. Chọn format JSON.
  5. Lưu. Sapo sẽ gửi test request — OpsOne trả 200 OK.
Lưu ý bảo mật: Webhook URL public — bất cứ ai biết URL đều có thể gửi request giả. OpsOne verify signature bằng header X-Sapo-Hmac-Sha256. Anh/chị phải cấp webhook_secret trong tab Tích hợp để hệ thống xác thực. Không có secret → webhook bị từ chối 401.

9. Xử lý sự cố thường gặp

Đơn Sapo không sync về OpsOne sau 10 phút

Check theo thứ tự:

  1. sapo_enabled = 1? Vào Cài đặt → Tích hợp, đảm bảo toggle "Kích hoạt đồng bộ" đang bật.
  2. Scheduler còn chạy? Liên hệ support, họ check pm2 logs tbbv-ops | grep sapo trên server.
  3. API key còn hạn? Bấm "Test kết nối" — nếu 401, lấy lại token từ Sapo admin.
  4. IP server bị block? Sapo đôi khi rate-limit hoặc geo-block. Liên hệ Sapo support để whitelist IP 157.245.159.48.
  5. Đơn có nằm trong khoảng filter? Đơn quá cũ (trước thời điểm bật sync) sẽ không tự kéo — phải backfill thủ công.
Push thanh toán lên Sapo bị lỗi 400 hoặc 404

Nguyên nhân thường gặp:

  • 404: Đơn đã bị xóa trên Sapo (admin Sapo xóa thủ công) → OpsOne không tìm thấy đơn để gắn transaction.
  • 400: Số tiền push lớn hơn số tiền đơn (vd đơn 100K, OpsOne push 120K) → Sapo từ chối.
  • 422: Sai gateway code (vd OpsOne gửi "cash" nhưng Sapo cấu hình không có method này) → vào Cài đặt → mapping payment method.
Tồn kho lệch giữa Sapo và OpsOne

Sapo là nơi giữ tồn "kho POS / kho bán" thật. OpsOne giữ tồn "kho tổng" + "kho phân tích". Lệch nhẹ là bình thường khi:

  • Có hàng chuyển kho nội bộ OpsOne mà Sapo không biết.
  • Có nhập hàng vào OpsOne (PO) chưa đẩy lên Sapo.

Để 2 hệ khớp 100%, dùng tính năng Đồng bộ tồn 2 chiều trong tab Tích hợp (chạy 1 lần/ngày lúc đêm).

Webhook bị Sapo gọi nhưng OpsOne không tạo đơn

Check log webhook: vào Cài đặt → Webhook log. Thường do:

  • Signature verify fail (secret sai).
  • Payload format Sapo đổi mới (cần update adapter).
  • Đơn đã tồn tại từ Scheduler trước đó (Webhook đến sau → skip duplicate).

10. Sapo Disabled — bật/tắt tích hợp

Có khi anh/chị muốn tạm tắt sync (đổi shop Sapo, đang test, hoặc Sapo bảo trì). Vào tab Tích hợp → tắt toggle "Kích hoạt đồng bộ Sapo". Cờ sapo_enabled chuyển về 0.

Khi sync đang tắt

Cách bật lại: Quay vào Cài đặt → Tích hợp → bật toggle. Lần Pull đầu tiên sau khi bật lại sẽ kéo tất cả đơn mới phát sinh trong khoảng thời gian tắt (Sapo lưu lịch sử 30 ngày).

11. Ba tình huống thực tế

Tình huống 1 — Shop bán lẻ nhỏ chỉ dùng Sapo POS
Doanh thu ~30-100 triệu/tháng · 1 cửa hàng vật lý · không bán online

Anh/chị bán hàng tại quầy bằng máy POS Sapo. OpsOne dùng để theo dõi công nợ NCC, dòng tiền, lãi lỗ.

Sapo POS bán
→
Pull mỗi 5'
→
OpsOne ghi nhận doanh thu
→
Báo cáo P&L tự động

Cấu hình tối thiểu: chỉ cần làm bước 3.1 → 3.4. Không cần Webhook. Push thanh toán cũng không cần vì khách trả ngay tại POS, Sapo đã ghi paid.

Tình huống 2 — Shop có Shopee + Sapo + Zalo
Doanh thu ~200-500 triệu/tháng · đa kênh · 1 kho

Anh/chị nhận đơn từ 3 nguồn: Shopee (qua Sapo Omnichannel), khách Sapo POS tại cửa hàng, Zalo OA (nhân viên tạo đơn tay trong OpsOne).

Shopee
→
Sapo Omni
→
OpsOne (Pull)
+
Zalo → OpsOne (manual)

Cấu hình khuyến nghị: bật Webhook để Shopee về real-time (sale 12.12 không lo trễ), kích hoạt Push thanh toán để báo cáo doanh thu khớp với báo cáo Sapo. Channel filter trong OpsOne dùng để xem hiệu suất từng sàn.

Tình huống 3 — Multi-store Sapo + multi-warehouse
Doanh thu > 1 tỷ/tháng · 3-10 cửa hàng Sapo · 2-5 kho

Anh/chị có nhiều cửa hàng Sapo (mỗi chi nhánh 1 shop riêng) và nhiều kho. Cần OpsOne tổng hợp lại.

Sapo HCM
+
Sapo HN
+
Sapo Đà Nẵng
→
OpsOne tổng

Cấu hình: tạo nhiều "Sapo Connection" trong tab Tích hợp, mỗi connection 1 cặp credentials + 1 store_id riêng. OpsOne map đơn từng store về warehouse tương ứng dựa trên rule mapping (vd sapo_store_hcm → warehouse_id 5). Báo cáo có filter theo cửa hàng + kho. Tính năng multi-store đang trong Beta — liên hệ support để bật.

12. Câu hỏi thường gặp

Sapo và OpsOne, đâu là "source of truth"?

Tùy loại dữ liệu:

  • Đơn hàng: Sapo là gốc (đơn sinh ra ở Sapo trước, OpsOne Pull về).
  • Thanh toán: OpsOne là gốc (phiếu nhận tiền approve ở OpsOne, push lên Sapo).
  • Tồn kho: tùy module — Sapo giữ tồn POS, OpsOne giữ tồn tổng/phân tích. Đồng bộ 2 chiều 1 lần/ngày.
  • Khách hàng + NCC + Sản phẩm: OpsOne là gốc. ⛔ Từ 13/08/2026 OpsOne KHÔNG còn đẩy SẢN PHẨM sang Sapo (CEO chốt: OpsOne là nơi quản lý sản phẩm). Sapo chỉ còn nhận ĐƠN từ sàn và đồng bộ TỒN KHO.
Đơn Sapo đã hủy có sync về OpsOne không?

Có. Khi đơn bị hủy trên Sapo, lần Pull tiếp theo (hoặc Webhook cancel) sẽ cập nhật đơn OpsOne sang trạng thái "Đã hủy" + ghi lý do. Đơn không bị xóa khỏi DB — vẫn giữ lại để audit. Nếu đơn đã có phiếu nhận tiền approved, hệ thống sẽ cảnh báo và yêu cầu hoàn tiền thủ công trước khi đánh dấu cancel.

Marketplace Shopee có thể tích hợp trực tiếp không qua Sapo không?

Hiện tại khuyến nghị qua Sapo. Adapter Shopee Partner API trực tiếp đang trong Beta nội bộ, dự kiến public Q3/2026. Lý do chậm: Shopee API phức tạp (cần đăng ký Shopee Partner, review app, OAuth dài), trong khi Sapo Omnichannel đã làm sẵn việc này.

Sapo đã nhận transaction từ OpsOne rồi mà vẫn show "Chưa thanh toán"?

Có 2 nguyên nhân:

  • Sapo cache: Sapo admin caching 1-2 phút. Bấm F5 sau 2 phút.
  • Transaction kind sai: OpsOne push kind = "sale", nhưng Sapo expect kind = "capture" cho 1 số config gateway. Liên hệ support để kiểm tra adapter mapping.
Disable Sapo tạm thời có làm mất dữ liệu không?

Không. Tắt sapo_enabled chỉ tạm dừng Scheduler + Push. Đơn đã sync vẫn nằm nguyên trong OpsOne. Credentials cũng được giữ lại — bật lại là chạy tiếp. Lần Pull đầu tiên sau khi bật lại sẽ catch-up các đơn phát sinh trong khoảng thời gian tắt (giới hạn 30 ngày lùi về trước).

OpsOne có hỗ trợ multi-store Sapo không?

Có, trong Beta. 1 project OpsOne kết nối nhiều shop Sapo, mỗi shop 1 cặp credentials. Đơn từ mỗi shop được gắn sapo_store_id riêng để báo cáo phân tích. Cần liên hệ support bật tính năng. Sau khi bật, UI Cài đặt sẽ hiện nút "Thêm Sapo Connection".

Nếu tôi đổi shop Sapo mới (đổi tên miền) thì sao?

Vào Cài đặt → Tích hợp → cập nhật sapo_store + sapo_api_key + sapo_token mới. Đơn cũ từ shop cũ vẫn nằm trong OpsOne (không bị xóa), đơn mới sẽ kéo từ shop mới. Lưu ý: sapo_id của 2 shop có thể trùng số → tránh confusion bằng cách archive đơn cũ trước khi đổi shop.

Webhook Sapo có miễn phí không?

Webhook phía Sapo là tính năng miễn phí của Sapo (mọi gói đều có). Phía OpsOne cũng không tính thêm phí cho việc nhận Webhook. Chỉ Push tới các sàn TMĐT khác (ngoài Sapo) qua Partner API riêng có thể phát sinh phí theo gói.

Cần hỗ trợ tích hợp?

Đội kỹ thuật OpsOne giúp anh/chị cấu hình Sapo + Shopee miễn phí trong gói Pro trở lên. Khách Free có thể tự làm theo hướng dẫn này.

Xem các gói Liên hệ hỗ trợ
© OpsOne AI · Hướng dẫn tích hợp Sapo & Shopee · cập nhật 2026-06-05
Dùng OpsOne trên điện thoại
Quét mã bằng camera, chấm công GPS kèm ảnh, mở khoá bằng vân tay.
App Store Google Play