tgpay cryptoAPI
crypto-payapiwebhookssignature

Tài liệu API: webhook

5 phút đọcCập nhật lần cuối: 9 thg 10, 2026

Webhook đẩy sự kiện về máy chủ của bạn sau khi chúng xảy ra. Hãy đặt Webhook URL (không bắt buộc) cho ứng dụng của bạn ở Thêm → Merchant API; từ đó nền tảng POST một JSON body có chữ ký cho mỗi sự kiện bạn đã đăng ký.

Cấu trúc sự kiện

{
  "update_id": 123,
  "update_type": "invoice_paid",
  "request_date": "2026-08-11T12:00:00Z",
  "payload": { … }
}

update_id giữ nguyên qua các lần gửi lại của cùng một sự kiện — hãy chống trùng theo trường này. request_date được ghi theo từng lần gửi. payload là đối tượng đầy đủ ứng với loại sự kiện: đối tượng invoice cho các sự kiện hóa đơn, đối tượng check, transfer hoặc subscription (cấu trúc nằm trên các trang tài liệu tương ứng).

Các loại sự kiện

update_typeĐược gửi khiPayload
invoice_paidmột hóa đơn được thanh toán — không cần bật riêngđối tượng invoice
invoice_expiredmột hóa đơn quá hạn mà chưa ai trảđối tượng invoice
check_activatedmột Lì xì hoặc phần của một người nhận được nhậnđối tượng check; lượt nhận theo danh sách còn có activated_slot
check_expiredLì xì theo danh sách hết hạn, phần chưa nhận được trả về ứng dụngđối tượng check kèm recipients và các giá trị claimed_at
transfer_completedlệnh chuyển hoàn tất hoặc khoản chi trả qua blockchain được xác nhậnđối tượng transfer hoặc withdrawal
transfer_returnedlệnh chuyển đang chờ chưa được nhận được trả về ứng dụng, hoặc khoản chi trả qua blockchain thất bại và tiền tạm giữ được trả lạiđối tượng transfer hoặc withdrawal
refund_completedmột lần hoàn tiền được thực hiệnđối tượng invoice kèm các trường refunded_*
subscription_activatedmột người dùng đăng ký góiđối tượng subscription
subscription_chargedmột kỳ được thu tiền — charge.kind cho biết là kỳ nào: initial, renewal hoặc resubscribeđối tượng subscription + charge: {period_no, kind, asset, amount, fee, paid_at}
subscription_cancelledmột gói đăng ký bị hủy, dù do bên nàođối tượng subscription
subscription_expiredhết thời gian gia hạn mà vẫn chưa trảđối tượng subscription

Khoản chi trả qua blockchain tạo trong ứng dụng cũng dùng các sự kiện transfer này. Payload có kind: "withdrawal", các trường mạng như network, address, txid và trạng thái completed hoặc failed. transfer_id của chúng thuộc dãy ID riêng; hãy phân biệt payload bằng kind trước khi dùng ID. Tài liệu OpenAPI tải xuống mô tả cả hai dạng payload.

Mọi loại trừ invoice_paid đều cần bật thủ công (một phần mở rộng so với Crypto Bot — phần tích hợp chỉ xử lý các sự kiện chuẩn của Crypto Bot sẽ không nhận update_type khác trừ khi bạn chủ động bật thêm). Bật cho từng ứng dụng ở mục Sự kiện webhook bổ sung trong mục Webhook của ứng dụng — các nút gạt dùng đúng định danh trong bảng trên. Lưu webhook URL để nhận sự kiện.

Kiểm tra chữ ký

Mỗi lần gửi đều mang header TgPayCrypto-API-Signature (TgCryptoPay-API-Signature và Crypto-Pay-API-Signature là tên gọi thay thế để tương thích, cùng một giá trị): chuỗi hex HMAC-SHA256 của nội dung thô trong yêu cầu, dùng khóa là bản băm SHA-256 của token API chính của ứng dụng. Đây đúng là cơ chế của Crypto Bot, nên code kiểm tra sẵn có chạy nguyên vẹn:

import hashlib, hmac

secret = hashlib.sha256(API_TOKEN.encode()).digest()
expected = hmac.new(secret, raw_body, hashlib.sha256).hexdigest()
ok = hmac.compare_digest(expected, headers["TgPayCrypto-API-Signature"])

Hãy kiểm tra trên đúng các byte thô nhận được — một bản đã phân tích rồi tuần tự hóa lại có thể khác từng byte và làm hỏng phép kiểm tra. Chỉ token chính mới ký; token giới hạn quyền không bao giờ ký. Đổi token chính là đổi luôn khóa ký webhook ngay lập tức, nên hãy cập nhật secret trên máy chủ của bạn trong cùng một lượt.

Gửi và thử lại

  • Một lần gửi được tính là thành công khi nhận được phản hồi 2xx bất kỳ trước khi lần gửi hết thời gian chờ. Phản hồi sớm và xử lý tác vụ dài riêng.
  • Mã lỗi, hết thời gian chờ hoặc lỗi kết nối khiến hệ thống thử lại với khoảng cách tăng dần, tới giới hạn số lần của nền tảng. Không bảo đảm sự kiện được giao; dùng getInvoices để đối soát thanh toán sau sự cố.
  • Sau lần cuối cùng, lần gửi đó bị bỏ. Bản thân webhook URL không bao giờ bị tự động tắt — một endpoint chập chờn không âm thầm hủy đăng ký ứng dụng của bạn.
  • Vì có thử lại, handler của bạn phải idempotent: hãy chống trùng theo update_id trước khi làm gì.

⚠️ Kiểm tra trước khi giao hàng

Ai cũng POST được tới webhook URL của bạn. Cho tới khi chữ ký được xác minh thành công, hãy coi body là dữ liệu không đáng tin: đừng giao đơn hàng, đừng cộng tiền cho ai, đừng đánh dấu bất cứ gì là đã trả. Thứ tự an toàn là: kiểm tra chữ ký → chống trùng theo update_id → rồi mới hành động.