Đối soát thanh toán cho người bán crypto
Cách đối soát thanh toán crypto với đơn hàng và số dư của bạn: cần ghi gì, các kiểm tra hằng ngày, cách tìm webhook bị bỏ lỡ và thanh toán thiếu, cùng cách hạch toán phí và rút tiền.

Đối soát trả lời một câu hỏi: mọi đơn hàng bạn coi là đã trả có khớp với một khoản thanh toán thực sự đã đến không, và mọi khoản thanh toán đã đến có khớp với một đơn không? Với crypto việc này không khó, vì mỗi khoản thanh toán mang số đơn hàng của chính bạn, nhưng chỉ hiệu quả nếu bạn ghi đúng thứ cần ghi và kiểm tra theo lịch. Bài này chỉ cần ghi gì, chạy những kiểm tra nào và giải thích những chênh lệch bạn tìm thấy ra sao.
Bạn đang đối soát cái gì
Ba bộ bản ghi phải khớp nhau:
- Đơn hàng của bạn: bạn đã bán gì, bằng đô la Mỹ, và đơn nào bạn coi là đã trả.
- Nhật ký webhook của bạn: các thông báo Qvard đã gửi và bạn đã làm gì với từng cái.
- Bảng điều khiển Qvard: các khoản thanh toán và số dư như cổng thanh toán nhìn thấy.
API công khai không có route liệt kê hay đọc thanh toán, nên bạn không thể kéo phía cổng thanh toán vào một đoạn script. Bạn đối soát đơn hàng với nhật ký webhook của chính mình, rồi so sánh tổng với những gì bảng điều khiển hiển thị.
Cần ghi gì để việc đối soát khả thi
Đối soát dễ nếu dữ liệu có sẵn và đau đầu nếu không.
- Dùng số đơn hàng của chính bạn làm id thanh toán. Nó đi tới Qvard khi bạn tạo thanh toán và quay lại trong webhook, nên là khóa gắn mọi thứ lại.
- Ghi log mọi webhook, kèm
id,status, thời gian và quyết định của bạn: đã áp dụng, lặp lại, đơn không rõ hoặc khóa bị từ chối. Không bao giờ ghi khóa bí mật của bạn. - Lưu giá trị đơn bằng đô la tại thời điểm đặt đơn, và thời điểm bạn đánh dấu đã trả.
- Giữ id thanh toán Qvard từ phản hồi nếu bạn muốn dùng cho hỗ trợ.
Chỉ đánh dấu đơn đã trả từ webhook, do Qvard gửi khi thanh toán hoàn tất, và làm trình xử lý idempotent. Chi tiết trong cách bảo mật webhook thanh toán crypto.
Các kiểm tra hằng ngày
Ba truy vấn nhỏ bắt được gần như mọi thứ; ví dụ cho thấy chúng.
- Đơn chưa trả quá cửa sổ tỷ giá. Tỷ giá trên trang thanh toán được cố định trong một giờ. Một đơn vẫn đang chờ sau đó hoặc đã bị bỏ, hoặc thông báo của nó bị bỏ lỡ. Hãy xem các khoản thanh toán đó trong bảng điều khiển.
- Đơn đã trả mà không có sự kiện «completed». Nếu bạn đánh dấu đơn đã trả nhưng nhật ký không có thông báo hoàn tất, có thứ gì đó đã bỏ qua webhook, điều không bao giờ nên xảy ra. Hãy điều tra trước khi giao thêm.
- Tổng theo ngày. So sánh số lượng và tổng đô la của các đơn bạn đánh dấu đã trả với các khoản thanh toán bảng điều khiển hiển thị cho cùng ngày.
Khi bảng điều khiển hiện một khoản thanh toán đã hoàn tất mà đơn của bạn vẫn chưa trả, thông báo đã bị bỏ lỡ: gửi lại từ bảng điều khiển và để trình xử lý idempotent áp dụng.
-- Your side: every webhook you receive is logged with your decision.
CREATE TABLE qvard_events (
id BIGSERIAL PRIMARY KEY,
order_id TEXT NOT NULL, -- the id you sent to Qvard
status TEXT NOT NULL, -- completed, ...
decision TEXT NOT NULL, -- applied | repeat | unknown_order | rejected_key
received_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- 1. Orders still unpaid after the rate window: candidates for a missed notification.
SELECT id, amount_usd, created_at
FROM orders
WHERE state = 'awaiting_payment'
AND created_at < now() - interval '1 hour'
ORDER BY created_at;
-- 2. Orders you consider paid, with no logged "completed" event: investigate before fulfilling more.
SELECT o.id, o.amount_usd, o.paid_at
FROM orders o
LEFT JOIN qvard_events e ON e.order_id = o.id AND e.status = 'completed'
WHERE o.state = 'paid' AND e.id IS NULL;
-- 3. The daily total to compare with the Qvard cabinet.
SELECT date_trunc('day', paid_at) AS day, count(*) AS orders, sum(amount_usd) AS usd
FROM orders
WHERE state = 'paid'
GROUP BY 1
ORDER BY 1 DESC;Giải thích các chênh lệch bạn tìm thấy
Hầu hết các khoảng hở có một danh sách nguyên nhân ngắn.
- Thanh toán thiếu. Số tiền đến ít hơn đủ, nên thanh toán có trạng thái
partialvà webhook hoàn tất không được gửi. Đơn chưa trả; hãy đòi phần chênh lệch hoặc hoàn tiền. Xem cách xử lý thanh toán USDT bị thiếu. - Thông báo bị bỏ lỡ. Máy chủ của bạn ngừng lâu hơn cửa sổ thử lại (năm lần trong khoảng sáu phút), hoặc trả lời khác với đúng HTTP 200. Xem chiến lược thử lại webhook trong hệ thống thanh toán.
- Bản trùng. Cùng một sự kiện đến hai lần. Trình xử lý đúng ghi nó là lặp lại và không thay đổi gì.
- Đơn không rõ. Thông báo có id mà bạn không có. Kiểm tra lỗi gõ ở id bạn gửi và các khoản thanh toán tạo từ hệ thống khác với cùng khóa.
- Hoàn tiền. Hoàn tiền là khoản chuyển bạn tự gửi; ghi nó vào đơn gốc để tổng vẫn tự giải thích được.
Phí, số dư và rút tiền
Giá trị đô la của các đơn không giống với tiền trong ví của bạn.
- Hoa hồng. Không có phí đăng ký; hoa hồng riêng cho dự án của bạn và theo trang bảng giá bắt đầu từ 1%, có thể giảm xuống 0,1%. Ghi nó thành một dòng riêng.
- Phí mạng. Khách trả phí mạng của giao dịch chuyển. Bạn chỉ trả phí mạng khi rút về ví của mình.
- Rút tiền. Ghi từng lần với ngày, mạng và phí. Rút về tài khoản ngân hàng bằng tiền pháp định không khả dụng; nếu bạn quy đổi ra tiền mặt, bước đó diễn ra ngoài Qvard và có bản ghi riêng.
- Đồng coin và mạng. Các khoản thanh toán ở mạng khác nhau tích lũy riêng. Kiểm tra số dư theo tài sản và mạng, như trong phí mạng trong vận hành thanh toán crypto.
Hãy cập nhật cho kế toán của bạn: cách xử lý thuế và kế toán đối với khoản thu bằng crypto phụ thuộc vào quốc gia của bạn.
FAQ
Tôi có thể lấy các khoản thanh toán qua API để đối soát không?
API công khai không có route liệt kê hay đọc thanh toán. Hãy đối soát đơn hàng với nhật ký webhook của chính bạn, và so sánh tổng với các khoản thanh toán và số dư trong bảng điều khiển Qvard.
Làm sao ghép một khoản thanh toán với đơn hàng?
Bằng id. Bạn gửi số đơn hàng của chính mình khi tạo thanh toán, và cùng id đó được trả lại trong webhook.
Nếu bảng điều khiển hiện thanh toán đã hoàn tất mà đơn của tôi chưa trả thì sao?
Thông báo đã bị bỏ lỡ. Gửi lại từ bảng điều khiển; trình xử lý idempotent áp dụng nó an toàn.
Nên đối soát thường xuyên đến đâu?
Hằng ngày là mặc định hợp lý, cộng thêm cảnh báo khi một loạt yêu cầu webhook nhận lỗi.