Skip to main content

Account (nick)

Một tài khoản nhắn tin đã kết nối, ví dụ một nick Zalo. Mỗi account có channel, status, mode, capabilities và bắt buộc đi qua một proxy riêng.

Mode

Vòng đời trạng thái

Gửi vào nick chưa sẵn sàng trả 409 ACCOUNT_NOT_READY kèm details.status.

Capability

Mỗi kênh khai báo khả năng trong GET /channels và capabilities của account, ví dụ send_text, send_image, friend_requests, search_by_phone, message_stranger. Hành động ngoài khả năng trả 422 CAPABILITY_NOT_SUPPORTED. Công cụ MCP tự ẩn khi workspace không có nick nào hỗ trợ.

Định danh

ID công khai có tiền tố: acc_ (account), cnv_ (hội thoại), msg_ (tin nhắn, kể cả tin đang chờ gửi), med_ (media), evt_ (event webhook). Hãy coi chúng là chuỗi mờ. external_id / user_external_id là id phía kênh.

Gửi tin và client_msg_id

POST /messages bắt buộc client_msg_id (8 đến 64 ký tự). Máy chủ suy ra msg_ id từ giá trị này, nên retry sau lỗi mạng hay timeout không bao giờ gửi hai lần. message.id trả về chính là message.id trong webhook message.sent.
  • ?wait=true (mặc định): chờ tối đa 15 giây (45 giây với media). Quá hạn trả 202 với status: "pending".
  • message.id trong 202 luôn có hàng thật trong hội thoại: máy chủ tạo hàng pending trước khi xếp lệnh gửi. Hàng này luôn kết thúc ở sent hoặc failed (lệnh hết hạn, nick chưa kết nối, vượt giới hạn, hoặc quá 5 phút không có kết quả đều chuyển failed), không bao giờ treo mãi.
  • Gửi lại cùng client_msg_id: tin sent trả 200 với tin cũ; tin đang pending trả 202 với chính hàng đó và không gửi lại (lần gửi đầu có thể đã tới kênh); chỉ tin failed mới được gửi lại thật.
  • Phản hồi 202 không được lưu theo Idempotency-Key: gửi lại luôn thấy trạng thái hiện tại.

Phân trang

Danh sách trả { "data": [...], "next_cursor": "..." }. Truyền cursor để lấy trang kế, next_cursor: null là hết. Cursor là chuỗi mờ. Tối đa limit=100. Tin nhắn trả mới nhất trước. GET /conversations/:id/messages?direction=after&cursor=... dùng để poll tin mới: next_cursor luôn trỏ tới tin mới nhất vừa trả (hoặc giữ nguyên cursor bạn gửi khi chưa có tin mới), nên bạn dùng lại được ở lần poll kế tiếp.
Cursor dựa trên sent_at (giờ của kênh). Tin đến muộn với sent_at cũ hơn cursor (Zalo đồng bộ tin offline sau khi kết nối lại) sẽ không xuất hiện trong direction=after. Webhook và realtime là nguồn đầy đủ; poll chỉ là phương án dự phòng. Khi cần đối soát, đọc lại trang đầu với direction=before.