Creating zalo oa chatbot
Skill duongxthanh/claude-zalo-skills/skills/creating-zalo-oa-chatbot
Use when a chatbot/app needs to SEND Zalo Official Account (OA) messages to a user — handoff notifications, alerts, customer-service replies. Dùng khi cần cho chatbot gửi tin nhắn qua Zalo OA (thông báo handoff, nhắc lịch, trả lời CSKH). Guides creating a dedicated Zalo app, authorizing the OA, the OAuth code→token exchange, and wiring a token-manager that survives refresh_token rotation (crash sau ~25h nếu làm sai).From its SKILL.md
npx -y skills add duongxthanh/claude-zalo-skills --skill creating-zalo-oa-chatbotAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
8.0 KB, ~2.5k tokens by cl100k_base, as published. Nobody here has run it
Tích hợp Zalo OA vào chatbot (gửi tin từ app/script)
Tổng quan
Cho chatbot/script gửi tin nhắn qua Official Account (OA) của Zalo tới một người dùng — ví dụ agent gặp ca ngoài phạm vi thì handoff: bắn tóm tắt vào Zalo của nhân viên. Skill này đi từ tạo app Zalo riêng → cấp quyền OA → đổi OAuth code lấy token → wire helper gửi tin, kết thúc bằng 1 tin test gửi thật.
CS message vs ZNS. Skill này dùng
/message/cs(Customer Service) — chỉ gửi được cho người đã nhắn OA trong cửa sổ CS (Zalo giới hạn ~48h kể từ tin cuối của họ). Handoff nội bộ (gửi cho nhân viên chủ động nhắn OA) hợp với CS. Muốn gửi chủ động cho khách bất kỳ (nhắc lịch, marketing) → cần ZNS template trả phí, cơ chế khác.
Điểm cốt lõi khiến việc này dễ hỏng: refresh_token XOAY
Zalo xoay refresh_token MỖI lần bạn refresh access_token — token cũ vô hiệu ngay. access_token sống ~25h (expires_in≈90000). Hệ quả:
- Không lưu lại refresh_token mới ⇒ sau 25h app crash, không gửi được tin.
- Mỗi chatbot/app một Zalo app RIÊNG. Hai app/tiến trình xoay cùng một refresh_token sẽ vô hiệu token của nhau. Tách app = token độc lập, không đạp lên nhau.
zalo_oa.py (kèm skill) lo hết: cache access_token theo hạn, chỉ refresh khi hết hạn, và ghi đè refresh_token đã xoay trở lại file config.
Quy trình (làm 1 lần để lấy token)
1. Tạo app riêng + kích hoạt
developers.zalo.me → Tạo ứng dụng → đặt tên, chọn danh mục. Ghi lại App ID (công khai) và App Secret (BÍ MẬT — không commit). Vào Thông tin ứng dụng, điền Điện thoại + Email liên hệ để app chuyển "Đang hoạt động" (chưa kích hoạt thì không cấp quyền OA được).
2. Xác thực domain của redirect_uri
developers.zalo.me/app/<APP_ID>/verify-domain → thêm domain sẽ nhận code (vd https://your-bot.example.com). Verify bằng 1 trong 3: DNS TXT zalo-platform-site-verification=<token>, hoặc file HTML ở root, hoặc <meta name="zalo-platform-site-verification" content="<token>"> ở trang chủ. Chưa verify domain thì bước 3 không lưu được.
3. Khai Callback Url ở OA (chỗ hay nhầm nhất)
Vào Official Account → Thiết lập chung (/app/<APP_ID>/oa/settings) → điền "Official Account Callback Url" = đúng redirect_uri (domain vừa verify) → Cập nhật. Zalo sẽ tự sinh sẵn "Đường dẫn yêu cầu cấp quyền" khớp redirect_uri này.
⛔ ĐỪNG tự chế URL
oauth.zaloapp.com/v4/oa/permission?...redirect_uri=...rồi mở thẳng — sẽ dính-14003 Invalid redirect uri. redirect_uri phải được khai TRƯỚC ở field "Official Account Callback Url" thì Zalo mới chấp nhận. (Subdomain nền tảng free như*.onrender.comvẫn dùng được một khi đã verify domain + khai đúng field này.)
⚠️ ĐỪNG bấm "Liên kết với Official Account" ở trang
/oa/manage. Đó là cơ chế độc quyền 1 OA ↔ 1 app (cho Zalo Loginuser_id_by_app) — bấm sẽ tự hủy liên kết OA khỏi app khác đang dùng, phá setup đó. Handoff chỉ cần "cấp quyền" (không độc quyền, 1 OA cấp quyền cho nhiều app được).
4. Lấy code rồi đổi lấy token
Mở "Đường dẫn yêu cầu cấp quyền" (Zalo sinh ở bước 3) trên Chrome đã đăng nhập admin OA → tick đồng ý điều khoản → Cấp quyền. Trình duyệt redirect về redirect_uri?oa_id=...&code=XXXX → copy code (ngắn hạn, đổi ngay). Điền .zalo-config (xem dưới) rồi:
python3 zalo_oa.py path/to/.zalo-config exchange-code "XXXX"
Helper đổi code → access_token + refresh_token và lưu refresh_token vào config. Xong seed — từ đây helper tự xoay.
5. Lấy user_id người nhận
user_id là theo từng OA (OA-scoped), không phải số điện thoại. Người nhận (vd nhân viên) nhắn cho OA 1 tin (từ Zalo cá nhân của họ) để mở cửa sổ CS → rồi:
python3 zalo_oa.py path/to/.zalo-config recent
Đọc from_id của họ trong danh sách (listrecentchat, tối đa 10 hội thoại gần nhất, src=1 là user gửi). Bỏ vào ZALO_HANDOFF_USER_ID.
Config & wiring
Config — <project>/config/.zalo-config (copy từ .zalo-config.example):
ZALO_APP_ID=1234567890
ZALO_APP_SECRET=xxxxxxxx
ZALO_OA_ID=9876543210
ZALO_REFRESH_TOKEN= # helper tự điền sau exchange-code, rồi tự xoay
ZALO_HANDOFF_USER_ID= # user_id lấy ở bước 5
Gitignore secret — thêm vào <project>/.gitignore: **/.zalo-config (chỉ commit file .example). Xác nhận đã ignore trước khi commit.
Wire vào chatbot — copy zalo_oa.py vào project, build đường dẫn config tuyệt đối từ __file__ (cron/chạy từ thư mục con sẽ không miss config):
from pathlib import Path
from zalo_oa import ZaloOA
CFG = Path(__file__).resolve().parent / "config" / ".zalo-config"
oa = ZaloOA(str(CFG))
oa.send(user_id, "🔔 Có khách cần tư vấn — anh/chị vào chốt giúp nhé.")
# Handoff mặc định: oa.send(oa.cfg["ZALO_HANDOFF_USER_ID"], text)
Verify — gửi thử: python3 zalo_oa.py config/.zalo-config send - "test handoff".
Quick reference
| Cần | Cách |
|---|---|
| App mới | developers.zalo.me → Tạo ứng dụng → App ID + Secret |
| redirect_uri hợp lệ | verify-domain → khai ở OA → Thiết lập chung → Official Account Callback Url |
Lấy code | mở "Đường dẫn yêu cầu cấp quyền" (Zalo sinh) trên Chrome, admin OA cấp quyền |
| code → token | zalo_oa.py <cfg> exchange-code <CODE> (grant_type=authorization_code) |
| access_token hết hạn | helper tự refresh + xoay refresh_token (grant_type=refresh_token, header secret_key) |
| Gửi tin | POST openapi.zalo.me/v3.0/oa/message/cs, header access_token |
| Lấy user_id | người nhận nhắn OA trước → zalo_oa.py <cfg> recent (listrecentchat) |
Lỗi thường gặp
-14003 Invalid redirect uri→ redirect_uri chưa khai ở "Official Account Callback Url", hoặc chưa verify domain. Đừng tự ghép URL permission bằng tay.- App crash sau ~25h /
-124invalid access token → không persist refresh_token đã xoay. Dùng helper này (ghi đè token vào config). Đừng để 2 tiến trình cùng xoay 1 refresh_token. - Bấm nhầm "Liên kết OA" → hủy liên kết OA khỏi app khác. Chỉ dùng "cấp quyền".
-32/ ngoài cửa sổ CS → người nhận chưa nhắn OA gần đây. Bảo họ nhắn OA 1 tin trước; hoặc chuyển sang ZNS nếu cần chủ động.- Không thấy người cần lấy user_id trong
recent→ họ chưa gửi tin (chỉ "Quan tâm" OA không đủ), hoặc đã trôi quá 10 hội thoại gần nhất. - Commit nhầm secret/token → gitignore
.zalo-configTRƯỚC. App Secret + refresh_token không bao giờ vào repo/log/chat. - Chạy
exchange-codevới code cũ →codengắn hạn, hết hạn nhanh. Lấy xong đổi ngay.
What ships with it: 3 files
16.5 KB alongside SKILL.md, 2 of them executable
- test_zalo_oa.pyruns6.4 KB
- .zalo-config.example780 B
- zalo_oa.pyruns9.3 KB