Quickstart
Integrasi end-to-end di sandbox: buat order, kunci kurs, tampilkan QR, terima pembayaran, dan verifikasi webhook. Semua contoh memakai API key merchant Anda.
Sebelum mulai
- Akun merchant aktif di dashboard.hashpay.id.
- API key dari Settings → API Key (dapat dirotasi kapan saja).
- Base URL sandbox:
https://api.hashpay.id/api/v2/testnet/ - Token uji gratis dari faucet testnet.
export HASHPAY_BASE="https://api.hashpay.id/api/v2/testnet"
export HASHPAY_API_KEY="hp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
export MERCHANT_ID="10001"1. Buat order
/merchant/fiat/orderorder_no adalah nomor unik dari sistem Anda. amount dalam satuan fiat terkecil-nya (IDR tanpa desimal).
curl -X POST "$HASHPAY_BASE/merchant/fiat/order" \
-H "api-key: $HASHPAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"merchant_id": "'"$MERCHANT_ID"'",
"order_no": "INV-2026-0001",
"amount": "150000",
"name": "Budi Santoso",
"email": "budi@example.com"
}'{
"status_code": 201,
"message": "success",
"data": {
"request": {
"order_no": "INV-2026-0001",
"merchant_id": "10001",
"amount": "150000",
"currency": "IDR",
"status": "Created"
},
"url": "https://pay.hashpay.io?key=...",
"key": "...",
"expired_at": 1821387856
}
}2. Kunci kurs & hitung fee
/merchant/fiat/checkOrderRateTentukan token dan jaringan, lalu kami mengunci kurs dan menghitung fee. Nominal crypto yang harus dibayar pelanggan sudah final di langkah ini — QR nanti tidak akan berubah.
curl -X POST "$HASHPAY_BASE/merchant/fiat/checkOrderRate" \
-H "api-key: $HASHPAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"merchant_id": "'"$MERCHANT_ID"'",
"transactionID": "INV-2026-0001",
"tokenAddress": "0xaD322e530C15330442841b4C400D730103B0af87",
"network": "ETHEREUM"
}'{
"data": {
"amount_crypto": "5.616189",
"crypto_rate": "17805.23",
"fees": [
{ "name": "Platform Fee", "fee_amount_crypto": "0.112324", "is_included": true }
],
"total_fee_amount_crypto": "0.112324",
"total_amount_crypto": "5.616189"
}
}3. Buat QR & alamat deposit
/pgqr/fiat/createRespons berisi qrValue (EIP-681 / deep link wallet) dan destinationAddress — alamat deposit unik yang hanya berlaku untuk order ini. Tampilkan QR dan nominal totalAmount ke pelanggan.
curl -X POST "$HASHPAY_BASE/pgqr/fiat/create" \
-H "api-key: $HASHPAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"merchant_id": "'"$MERCHANT_ID"'",
"transactionID": "INV-2026-0001",
"tokenAddress": "0xaD322e530C15330442841b4C400D730103B0af87",
"network": "ETHEREUM",
"walletType": "METAMASK"
}'{
"data": {
"request": {
"amount": "5.616189",
"feeAmount": "0.112324",
"feeIsIncluded": true,
"uniqueCode": "470",
"uniqueCodeAmount": "0.000470",
"totalAmount": "5.616659",
"totalAmountFiat": "100000.00",
"destinationAddress": "0x2AC2223419f32a6Aab57D9d4cb3210C97Bc62d51",
"qrValue": "ethereum:0xaD32...@11155111/transfer?address=0x2AC2...&uint256=5616659",
"expiredAt": 1789854291
},
"qrValue": "..."
}
}4. Pantau status order
/merchant/fiat/getOrderPolling berguna sebagai fallback, tetapi produksi sebaiknya mengandalkan webhook.
curl -X POST "$HASHPAY_BASE/merchant/fiat/getOrder" \
-H "api-key: $HASHPAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"merchant_id": "'"$MERCHANT_ID"'", "order_no": "INV-2026-0001"}'5. Terima webhook
Setelah order Success, kami mengirim POST ke notification_url merchant dengan header X-Hashpay-Signature. Verifikasi tanda tangan sebelum memproses:
import crypto from "node:crypto";
export function verifyHashpaySignature(rawBody, signatureHeader, apiKey) {
const expected =
"sha256=" +
crypto.createHmac("sha256", apiKey).update(rawBody).digest("hex");
const a = Buffer.from(expected);
const b = Buffer.from(signatureHeader ?? "");
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
// app.post("/hashpay/webhook", express.raw({ type: "*/*" }), (req, res) => {
// if (!verifyHashpaySignature(req.body, req.header("X-Hashpay-Signature"), process.env.HASHPAY_API_KEY)) {
// return res.status(401).send("invalid signature");
// }
// const event = JSON.parse(req.body.toString());
// // idempotent: gunakan X-Hashpay-Idempotency-Key
// res.status(200).send("ok");
// });Contoh lengkap (Node.js)
const BASE = process.env.HASHPAY_BASE;
const KEY = process.env.HASHPAY_API_KEY;
const MERCHANT = process.env.MERCHANT_ID;
const call = async (path, body) => {
const res = await fetch(`${BASE}${path}`, {
method: "POST",
headers: { "api-key": KEY, "Content-Type": "application/json" },
body: JSON.stringify(body),
});
const json = await res.json();
if (json.status_code >= 400) throw new Error(json.message);
return json.data;
};
const orderNo = `INV-${Date.now()}`;
const TOKEN = "0xaD322e530C15330442841b4C400D730103B0af87"; // USDT testnet
await call("/merchant/fiat/order", {
merchant_id: MERCHANT,
order_no: orderNo,
amount: "150000",
});
await call("/merchant/fiat/checkOrderRate", {
merchant_id: MERCHANT,
transactionID: orderNo,
tokenAddress: TOKEN,
network: "ETHEREUM",
});
const qr = await call("/pgqr/fiat/create", {
merchant_id: MERCHANT,
transactionID: orderNo,
tokenAddress: TOKEN,
network: "ETHEREUM",
walletType: "METAMASK",
});
console.log("Kirim tepat:", qr.request.totalAmount, "USDT");
console.log("Ke alamat :", qr.request.destinationAddress);
console.log("QR value :", qr.request.qrValue);Selesai — langkah berikutnya
- Webhooks: tanda tangan, retry, dan idempotensi.
- Transaction lifecycle: semua status & artinya.
- Payment links: link pembayaran tanpa order manual.
- Settlement: pencairan dana ke wallet Anda.