Nút thanh toán crypto cho website
Cách thêm nút «Thanh toán bằng crypto» vào website: vì sao nút không thể gọi trực tiếp API thanh toán, mẫu ba bước, mã front-end và máy chủ chạy được và những gì cần bảo vệ.

Nút «Thanh toán bằng crypto» dễ thêm, nhưng không thể là một đoạn mã sao chép dán: tạo thanh toán cần khóa API bí mật của bạn, thứ không bao giờ được đến trình duyệt. Vì vậy nút phải giao tiếp với máy chủ của bạn, máy chủ tạo thanh toán và trả về địa chỉ trang thanh toán. Bài này trình bày mẫu đó với mã chạy được và những điểm giữ cho nó an toàn.
Vì sao chưa có nút sao chép dán
Nhiều nhà cung cấp thanh toán đưa ra nút hoặc widget nhúng được. Qvard chưa có nút không cần mã: liên kết thanh toán đang được phát triển. Trang thanh toán nhúng đã sẵn sàng làm widget cho website của bạn. SDK đã sẵn sàng. Hôm nay việc tích hợp qua API, và API được xác thực bằng khóa bí mật trong header Authorization: Bearer.
Khóa đó có thể tạo thanh toán cho dự án của bạn, nên phải ở lại máy chủ. Một nút mang khóa trong mã front-end sẽ trao nó cho mọi khách truy cập. Đây không phải hạn chế cần lách; chính là lý do mẫu bên dưới có một bước ở máy chủ.
Mẫu: nút, endpoint của bạn, trang thanh toán
Ba bước tạo nên một nút hoạt động:
- Nút gửi yêu cầu tới một endpoint trên máy chủ của bạn, nói khách muốn mua gì (sản phẩm, gói), không nói giá bao nhiêu.
- Endpoint của bạn tra giá, tạo bản ghi đơn hàng của bạn và gọi Qvard: một
POSTtớihttps://api.qvard.com/api/v1/paymentvới khóa trong headerAuthorization: Bearervà JSON có số đơn hàng làmid, số tiền làmpricebằng đô la Mỹ. Phản hồi là201kèmredirectUrl. - Trình duyệt được chuyển hướng tới
redirectUrlđó, trang thanh toán do Qvard lưu trữ, nơi khách chọn tài sản và mạng rồi trả từ ví.
Không có gì bí mật chạm tới trang, và bản thân trang thanh toán do Qvard lưu trữ, nên bạn không phải xây một trang thanh toán crypto.
Front-end: một nút và một lần chuyển hướng
Nút cần khoảng mười lăm dòng. Nó tự vô hiệu hóa trong lúc yêu cầu chạy, gửi mã định danh sản phẩm và khi thành công đưa trình duyệt tới địa chỉ được trả về. Khi lỗi, nó bật lại và hiện thông báo, để khách có thể thử lại.
Hãy nhớ một quy tắc: trình duyệt gửi cái gì được mua, không bao giờ gửi bao nhiêu. Nếu số tiền lấy từ trang, ai cũng có thể mở công cụ nhà phát triển và biến gói 49 đô la thành khoản thanh toán một đô la.
<button id="pay-crypto" data-product="pro-plan">Pay with crypto</button>
<script>
document.getElementById('pay-crypto').addEventListener('click', async (event) => {
const button = event.currentTarget;
button.disabled = true;
try {
// Send only WHAT is being bought; the server decides the price.
const res = await fetch('/api/crypto-checkout', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ product: button.dataset.product })
});
if (!res.ok) throw new Error('checkout failed');
const { redirectUrl } = await res.json();
window.location.assign(redirectUrl); // the Qvard hosted payment page
} catch (e) {
button.disabled = false;
alert('Could not start the payment. Please try again.');
}
});
</script>Máy chủ: giá, đơn hàng, thanh toán
Endpoint trong ví dụ làm bốn việc:
- Tra giá từ một bảng trên máy chủ và từ chối sản phẩm không rõ.
- Tạo đơn hàng của bạn và dùng số của nó làm
idthanh toán. Webhook sau đó tìm đơn nhờ số này. - Gọi Qvard và chỉ trả
redirectUrlcho trình duyệt. Câu trả lời400(«Error validation», kèm thông báo theo từng trường) nghĩa là nội dung sai;401nghĩa là khóa sai. Cả hai đều không nên thử lại khi chưa thay đổi. - An toàn khi lặp lại. Gửi cùng
idcho cùng phương thức thanh toán trả về khoản thanh toán hiện có, nên khách nhấp hai lần không tạo hai khoản.
Thêm giới hạn tốc độ cho endpoint để không ai tạo được hàng nghìn đơn chưa thanh toán, và yêu cầu người dùng đăng nhập hoặc captcha nếu sản phẩm của bạn cần.
import express from 'express';
import crypto from 'node:crypto';
const app = express();
const PRICES_USD = { 'pro-plan': 49 }; // prices live on the server, never in the browser
app.post('/api/crypto-checkout', express.json(), async (req, res) => {
const price = PRICES_USD[req.body.product];
if (!price) return res.sendStatus(400);
const orderId = await db.orders.create({ product: req.body.product, amountUsd: price }); // your own order number
const response = await fetch('https://api.qvard.com/api/v1/payment', {
method: 'POST',
headers: { Authorization: 'Bearer ' + process.env.QVARD_API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ id: String(orderId), price })
});
if (response.status !== 201) return res.sendStatus(502);
const { redirectUrl } = await response.json();
res.json({ redirectUrl });
});Sau cú nhấp: webhook quyết định
Chuyển hướng khách tới trang thanh toán là bắt đầu thanh toán; chưa phải hoàn tất. Khi thanh toán hoàn tất, Qvard gọi callback URL đã lưu trong dự án với id của bạn và trạng thái completed. Chỉ khi đó mới cấp quyền truy cập hoặc đánh dấu đơn đã trả. Endpoint phải trả lời đúng HTTP 200 và an toàn khi chạy hai lần; xem cách bảo mật webhook thanh toán crypto.
Chưa có URL quay lại sau khi thanh toán, nên khách tự quay lại trang của bạn. Hãy cho họ một trang hiển thị trạng thái đơn hàng thực và tự làm mới khi còn đang chờ, không phải trang cảm ơn mặc định coi như thành công.
Giá cố định, số tiền thay đổi và bước tiếp theo
- Giá cố định (gói, sản phẩm) là trường hợp dễ: bảng trên máy chủ giữ chúng.
- Số tiền thay đổi (quyên góp, nạp tiền) cần kiểm tra ở máy chủ: mức tối thiểu, tối đa và kiểm tra số. Số tiền dưới mức tối thiểu của phương thức thanh toán đã chọn bị từ chối bằng
400. - Nhiều nút dùng chung một endpoint; chỉ khác mã định danh sản phẩm.
Hướng dẫn đầy đủ nằm trong cách nhận thanh toán crypto trên website, còn API trong API thanh toán crypto cho nhà phát triển. Hóa đơn demo cho thấy trang mà nút dẫn tới; điều kiện thương mại ở trang bảng giá.
FAQ
Tôi có thể đặt khóa API Qvard vào mã của nút không?
Không. Khóa có thể tạo thanh toán cho dự án của bạn và phải ở lại máy chủ. Nút nên gọi endpoint của riêng bạn, endpoint đó gọi Qvard.
Có widget nhúng hoặc nút không cần mã không?
Có, trang thanh toán nhúng đã sẵn sàng làm widget cho website của bạn. Nút không cần mã chưa có: liên kết thanh toán đang được phát triển. SDK đã sẵn sàng. Hôm nay việc tích hợp dùng API với một endpoint máy chủ nhỏ.
Giá nên lấy từ đâu?
Từ máy chủ của bạn, không bao giờ từ trình duyệt. Nút chỉ gửi cái được mua, còn máy chủ quyết định giá bằng đô la Mỹ.
Làm sao biết khách đã trả?
Từ webhook mà Qvard gửi khi thanh toán hoàn tất. Việc khách quay lại trang không phải bằng chứng thanh toán.
