tgpay cryptoAPI
crypto-payapireferencetokens

Tài liệu Merchant API

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

Các quy ước chung của mọi phương thức, cùng các phương thức tra cứu chỉ đọc. Trang chi tiết từng nhóm: hóa đơn và hoàn tiền, chuyển tiền và Lì xì, gói đăng ký, webhook.

API tuân theo quy ước Crypto Bot cho các phương thức được mô tả ở đây. Đổi base URL và token, rồi thử các phương thức tích hợp đang dùng trên testnet. Các chức năng bổ sung được đánh dấu phần mở rộng bên dưới.

Bản đặc tả OpenAPI 3.1 máy đọc được cũng có tại: crypto-pay-openapi.yaml · crypto-pay-openapi.json. Hãy nạp nó vào trình sinh code, API client hoặc công cụ AI, nhưng hãy xem cả trang từng phương thức: đặc tả có thể chưa cập nhật các phần mở rộng mới.

Base URL và xác thực

Mọi phương thức đều nằm ở https://app.tgpaycrypto.com/pay/api/<methodName>. Trên mạng thử nghiệm, base là https://testnet.tgpaycrypto.com/pay/api — ứng dụng và token riêng, coin không có giá trị.

Hãy xác thực mọi yêu cầu bằng token đặt trong header TgPayCrypto-API-Token (TgCryptoPay-API-Token, tên dùng trước ngày 2026-09-07, và Crypto-Pay-API-Token được chấp nhận như tên gọi thay thế để tương thích; nếu gửi nhiều header cùng lúc thì header chuẩn được ưu tiên). Token thiếu, sai hoặc đã bị thu hồi — cũng như token giới hạn quyền đã hết hạn, token của ứng dụng đã xóa hoặc có chủ sở hữu bị chặn — trả về 401 unauthorized.

Token có dạng <app_id>:<secret> và chỉ hiện một lần, lúc tạo hoặc lúc đổi token mới; máy chủ chỉ lưu bản băm của nó. Xem Bắt đầu dành cho lập trình viên.

Token và scope

Hai loại thông tin xác thực dùng chung một cách xác thực:

  • Token chính — toàn quyền với mọi phương thức, và là khóa duy nhất ký webhook.
  • Token giới hạn quyền (phần mở rộng) — tối đa 10 token chưa thu hồi, kể cả token đã hết hạn, cho mỗi ứng dụng. Mở Thêm → Merchant API, chọn ứng dụng rồi mở Quyền truy cập và token. Tạo token trong mục Token giới hạn quyền, mỗi token có một nhãn và một tập scope con. Thu hồi một token là tức thì và không đụng tới các token khác; đổi token chính cũng không đụng tới chúng. Token có thể có hạn sử dụng; sau đó không còn xác thực được.
ScopePhương thức mà nó mở
(mọi token hợp lệ)getMe, getCurrencies, getExchangeRates
readgetBalance, getStats, getInvoices, getChecks, getTransfers, getSubscriptionPlans, getSubscriptions
invoicescreateInvoice, deleteInvoice
refundsrefundInvoice
payoutstransfer, transferBatch
checkscreateCheck, deleteCheck
subscriptionscreateSubscriptionPlan, archiveSubscriptionPlan, cancelSubscription
webhooksupdateApp

Các scope cộng dồn và độc lập với nhau — invoices không kéo theo read, nên máy chủ chỉ tạo hóa đơn có thể dùng token không có quyền xem số dư hoặc lịch sử thanh toán. Gọi phương thức nằm ngoài phạm vi quyền của token sẽ trả về 403 scope_required. getMe cho biết scopes của token đang dùng (null với token chính) và token_name, nên bạn có thể kiểm tra quyền của token đang dùng.

Chế độ chi trả

Scope quyết định token được gọi những phương thức nào; còn chế độ chi trả của ứng dụng quyết định bất kỳ token nào của nó — kể cả token chính — được chi trả cho ai. Một ứng dụng mới chi trả được cho bất kỳ ai ngay từ phút đầu; chủ sở hữu có thể giới hạn người nhận bằng cách mở ứng dụng trong Thêm → Merchant API, rồi vào Cài đặt chi trả → Chi trả qua API. Giống hạn mức hằng ngày, cài đặt này giới hạn những gì người có token bị lộ có thể làm. Muốn mở rộng lại phạm vi người nhận, cần mã PIN hoặc sinh trắc học; API chỉ đọc được chế độ này (getMe → payout_mode).

payout_modetransfer, transferBatch và createCheck được làm gì
anychi trả cho bất kỳ người dùng nào, tạm giữ khoản chi trả cho một @username chưa biết, tạo Lì xì không gán người nhận — mặc định, đúng như Crypto Bot
allowlistchỉ chi trả cho những người dùng Telegram có trong danh sách người nhận của ứng dụng. Mọi người nhận được gán sẵn hoặc nêu trong danh sách Lì xì đều phải được phép nhận. Người khác, @username chưa biết và Lì xì không gán người nhận đều nhận 403 recipient_not_allowed
offkhông gì cả — mọi lệnh gọi chi trả đều trả về 403 payouts_disabled; hóa đơn, gói đăng ký, hoàn tiền và webhook vẫn chạy bình thường

Khi một khoản chi trả bị từ chối, chủ sở hữu được báo trong Telegram và có thể đổi chế độ. Hạn mức chi trả mỗi ngày vẫn áp dụng bên cạnh chế độ này. Còn được chi trả cho những mục đích nào thì do điều khoản Merchant API quy định.

Yêu cầu và phản hồi

  • Các phương thức đọc dùng GET với tham số trên query string. Các phương thức động tới tiền chỉ nhận POST — tham số truyền dưới dạng JSON body, form-urlencoded hoặc query param (body thắng khi xung đột); multipart/form-data bị từ chối.
  • Phản hồi do trình xử lý API trả về dùng chung một cấu trúc JSON: thành công {"ok": true, "result": …}, lỗi {"ok": false, "error": {"code": <HTTP status>, "name": "<error_name>"}}. Hãy rẽ nhánh theo error.name — đó là chuỗi máy đọc ổn định.
  • Tham số query sai kiểu trên phương thức GET (ví dụ offset=abc) có thể bị từ chối trước khi trình xử lý API chạy. Hãy kiểm tra mã trạng thái HTTP; đừng mặc định mọi phản hồi lỗi đều có cấu trúc trên. Gửi tham số query đúng kiểu dữ liệu yêu cầu.

Số tiền

  • Số tiền crypto là chuỗi thập phân theo đơn vị tài sản ("10.5") — không bao giờ là số JSON. Phản hồi còn kèm amount_minor (phần mở rộng): giá trị nguyên theo đơn vị nhỏ nhất, dưới dạng chuỗi, vì số nguyên cỡ wei có thể vượt giới hạn biểu diễn số nguyên chính xác của Number trong JavaScript.
  • decimals của từng tài sản lấy từ getCurrencies — hãy để phần tính toán số tiền chạy theo đó thay vì gán cứng.
  • Số tiền pháp định có tối đa 2 chữ số thập phân.
  • Tỷ giá là chuỗi thập phân, không bao giờ là số.

Phân trang

Các phương thức danh sách (getInvoices, getChecks, getTransfers, getSubscriptions) nhận offset (mặc định 0) và count (mặc định 100, tối đa 1000; getSubscriptions tối đa 500) và trả về {"items": […]}, mới nhất trước. Bộ lọc theo ID (invoice_ids, check_ids, transfer_ids) là danh sách số nguyên phân tách bằng dấu phẩy. Mọi dấu thời gian đều là chuỗi ISO 8601.

Idempotency: spend_id

Các phương thức động tới tiền nhận một khóa spend_id do bên gọi tự sinh (1–64 ký tự): bắt buộc với transfer và với từng phần tử của transferBatch, tùy chọn với createCheck và refundInvoice (phần mở rộng — vẫn nên dùng). Thử lại với cùng khóa và cùng tham số sẽ trả về kết quả gốc thay vì chuyển tiền hai lần, nên một yêu cầu hết thời gian chờ luôn an toàn để thử lại. Cùng khóa nhưng khác tham số trả về 409 idempotency_conflict; thử lại trong lúc lần gọi gốc còn đang chạy trả về 409 idempotency_in_progress.

Giới hạn tần suất

Tính theo từng ứng dụng, dùng chung cho mọi token của nó; vượt quá thì trả về 429 rate_limited:

Phương thứcGiới hạn
createInvoice, createCheck60 mỗi phút
refundInvoice30 mỗi phút
transfer30 mỗi phút
transferBatch10 mỗi phút
updateApp10 lần mỗi phút
createSubscriptionPlan20 lần mỗi phút

Có thể áp dụng thêm giới hạn yêu cầu. Khi gặp 429 rate_limited, tăng thời gian chờ trước khi thử lại. Trong lúc nền tảng bảo trì, các phương thức ghi trả về 503 maintenance còn các phương thức đọc vẫn chạy bình thường.

Phương thức tra cứu và tài khoản

getMe

GET /pay/api/getMe — không có tham số. Trả về danh tính của ứng dụng: app_id, name, payment_processing_bot_username, webhook_url, webhook_events (các loại webhook mở rộng mà ứng dụng đã bật), hai trường cho biết thông tin token scopes / token_name nói ở trên, và payout_mode (off / allowlist / any), daily_payout_max_usd_cents (0 = chủ sở hữu không đặt hạn mức) và daily_payout_spent_usd_cents (số đã chi trong 24 giờ gần nhất).

updateApp

POST /pay/api/updateApp — scope webhooks. Tham số tùy chọn: name (1–64 ký tự), webhook_url (URL HTTPS công khai; chuỗi rỗng để xóa) và webhook_events (mảng hoặc danh sách phân tách bằng dấu phẩy chứa các tên sự kiện mở rộng được hỗ trợ). Danh sách sự kiện rỗng chỉ giữ lại invoice_paid. Trả về cùng các trường ứng dụng như getMe.

getBalance

GET /pay/api/getBalance — không có tham số. Trả về một mảng, mỗi tài sản được hỗ trợ một dòng, kể cả khi bằng không: currency_code, available (số dư khả dụng), onhold (tiền Lì xì chưa được nhận và các khoản chi trả cho @username đang chờ) và amount_minor.

getCurrencies

GET /pay/api/getCurrencies — không có tham số. Danh sách chuẩn những gì API hỗ trợ: các dòng crypto (is_blockchain: true) và các loại tiền pháp định mà hóa đơn có thể định giá theo (is_fiat: true). Mỗi dòng mang code, name, decimals và cờ is_stablecoin.

getExchangeRates

GET /pay/api/getExchangeRates — không có tham số. Tỷ giá crypto sang tiền pháp định: source, target, rate (chuỗi thập phân) và is_valid. Các tỷ giá này chỉ mang tính tham khảo. is_valid: true không bảo đảm tỷ giá còn mới. Nếu không lấy được tỷ giá, kết quả có thể là mảng rỗng. Dùng số tiền và tỷ giá đã ghi trên hóa đơn để đối soát thanh toán thực tế.

getStats

GET /pay/api/getStats — tùy chọn start_at / end_at (ISO 8601; cửa sổ mặc định là 24 giờ gần nhất). Trả về volume (giá trị USD của các hóa đơn đã thanh toán trong khoảng đó, ước tính theo tỷ giá hiện tại; tài sản không có giá được tính là 0), conversion (đã trả/đã tạo, theo phần trăm), unique_users_count, created_invoice_count, paid_invoice_count, và hai mốc thực tế của cửa sổ. Ngày không đọc được sẽ trả về 400 invalid_date.

Lỗi mà mọi phương thức đều có thể trả về

HTTPerror.nameKhi nào
401unauthorizedtoken thiếu, sai hoặc đã bị thu hồi
403scope_requiredtoken không có scope của phương thức
403payouts_disabledchế độ chi trả của ứng dụng đang là off (chỉ các phương thức chi trả)
403recipient_not_allowedngười nhận không có trong danh sách người nhận của ứng dụng (chỉ các phương thức chi trả)
400invalid_requesttham số không đọc được hoặc không hợp lệ (POST)
403daily_cap_exceededvượt hạn mức chi trả hằng ngày của ứng dụng
403verification_requiredchủ sở hữu bị hạn chế giao dịch chi tiền; áp dụng cho chuyển tiền, Lì xì và hoàn tiền
503merchant_payouts_pausedtạm dừng trừ tiền từ số dư ứng dụng
429rate_limitedvượt giới hạn tần suất
503maintenancenền tảng đang bảo trì (các phương thức ghi)
500internal_errorlỗi máy chủ ngoài dự kiến

Các lỗi riêng của từng phương thức được liệt kê trên trang của phương thức đó.

Lỗi không theo cấu trúc JSON

Chỉ dựa vào phản hồi lỗi dạng văn bản thuần hoặc HTML thì chưa thể xác định lỗi đến từ lớp nào. Hãy kiểm tra trạng thái HTTP, nội dung và các header của phản hồi.

Nếu Cloudflare trả về error code: 1010, máy khách đã bị từ chối dựa trên dấu hiệu nhận dạng trình duyệt trước khi yêu cầu đến API. Phạm vi quyền của token không phải nguyên nhân gây ra lỗi Cloudflare này. User-Agent bị thiếu hoặc không chuẩn có thể kích hoạt lớp bảo vệ mạng. Hãy thử gửi header User-Agent có tên nhận diện máy khách của bạn, chẳng hạn MyShop/1.0, rồi gửi lại yêu cầu; cách này không đảm bảo khắc phục được lỗi. Nếu lỗi vẫn còn, hãy gửi cho bộ phận hỗ trợ trạng thái HTTP, nội dung và các header của phản hồi sau khi xóa token và cookie.