Developer
Dompet tetap
Beri setiap pelanggan Anda alamat deposit sendiri yang tidak pernah berubah, satu per jaringan. Setiap deposit masuk ke saldo Crypto Merchant Anda, dan server Anda diberi tahu pelanggan mana yang mengirimnya, sehingga Anda dapat mengisi saldo akun yang tepat.
Cara mendapatkan dompet tetap
403 sticky_wallets_unavailable. Endpoint ini memakai URL dasar, kunci rahasia, dan format error yang sama dengan bagian API lainnya.Sebelum memulai
- 1
Selesaikan penyiapan dan pilih koin Anda. Setiap pelanggan mendapat alamat di jaringan koin yang Anda terima (portal, Pengaturan).
- 2
Buat kunci rahasia. Di portal, buka Developer dan buat kunci API. Kunci hanya ditampilkan sekali: simpan di server Anda, misalnya sebagai
CM_SECRET_KEY, jangan pernah di halaman web atau aplikasi. - 3
Tambahkan endpoint webhook. Masih di Developer, tambahkan URL Anda dengan event
deposit.pending,deposit.confirmed, dandeposit.dropped(atau semua event). Simpan secret penandatanganannya,whsec_…, untuk memeriksa setiap permintaan.
Cara kerjanya
- 1
Pelanggan membuka halaman deposit di situs Anda.
- 2
Server Anda memanggil
POST /sticky-walletsdengan ID Anda sendiri untuk pelanggan tersebut. Panggilan pertama membuat alamatnya; setiap panggilan berikutnya mengembalikan alamat yang sama. - 3
Anda menampilkan alamat, beserta kode QR, untuk koin yang dipilih pelanggan.
- 4
Saat koin masuk, Anda menerima
deposit.pending, laludeposit.confirmedsetelah jaringan mengonfirmasinya. - 5
Saat menerima
deposit.confirmed, tambahkan saldo pelanggan yang disebutkan disticky_wallet.reference.
Mengambil dompet pelanggan
POST/sticky-wallets
Membuat dompet pelanggan pada panggilan pertama dan mengembalikan dompet yang sama pada setiap panggilan berikutnya: 201 jika baru dibuat, 200 setelahnya. Aman dipanggil setiap kali halaman deposit dibuka.
Parameter body
referenceWajibstring- ID Anda untuk pelanggan ini: 1 hingga 120 huruf, angka, atau
. _ : @ + -, diawali huruf atau angka. Satu dompet per referensi, untuk selamanya. labelOpsionalstring- Nama yang akan Anda lihat di portal. Mengirimnya lagi akan menggantinya.
metadataOpsionalobject- Objek milik Anda sendiri, hingga 4 KB. Mengirimnya lagi akan menggantinya.
curl https://cryptomerchant.online/api/v1/sticky-wallets \
-H "Authorization: Bearer $CM_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"reference": "user-1042",
"label": "Jane Doe",
"metadata": { "plan": "pro" }
}'// On your server, when a customer opens their deposit page
export async function depositAddresses(userId) {
const res = await fetch("https://cryptomerchant.online/api/v1/sticky-wallets", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CM_SECRET_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ reference: String(userId) }),
});
if (!res.ok) {
const { error } = await res.json();
throw new Error(`${error.code}: ${error.message}`);
}
const wallet = await res.json();
return wallet.addresses; // [{ network, address, coins: [...] }, …]
}Objek dompet tetap
idstring- ID dompet, diawali dengan
sw_. referencestring- ID Anda untuk pelanggan.
addressesarray- Satu entri per jaringan:
network(tron,evm,sol,btc, ataultc),address, dancoinsyang diterimanya. Alamatevmsama di Ethereum, BNB Smart Chain, Polygon, Base, dan Arbitrum. pending_networksarray- Jaringan yang alamatnya masih disiapkan, yang jarang terjadi. Panggil lagi dalam beberapa menit dan jaringan tersebut akan muncul di
addresses. created_atstring- Waktu dompet dibuat.
{
"id": "sw_8Kd2pQx7Vb1mNc3T",
"object": "sticky_wallet",
"reference": "user-1042",
"label": "Jane Doe",
"metadata": { "plan": "pro" },
"addresses": [
{
"network": "tron",
"address": "TXbajeGHq4Vb…",
"coins": [
{ "id": "TRX.TRON", "symbol": "TRX", "network": "Tron" },
{ "id": "USDT.TRON", "symbol": "USDT", "network": "Tron" }
]
},
{
"network": "evm",
"address": "0xE550EC6d…",
"coins": [
{ "id": "ETH.ETH", "symbol": "ETH", "network": "Ethereum" },
{ "id": "BNB.BSC", "symbol": "BNB", "network": "BNB Smart Chain" },
{ "id": "USDT.BSC", "symbol": "USDT", "network": "BNB Smart Chain" }
]
}
],
"pending_networks": [],
"created_at": "2026-10-29T18:20:41.000Z"
}Beri tahu pelanggan apa yang harus dikirim
Mencari dompet
GET/sticky-wallets
GET/sticky-wallets/{id}
Cari dompet berdasarkan referensi Anda, ambil satu berdasarkan ID-nya, atau telusuri semuanya halaman demi halaman, dari yang terbaru: limit dari 1 hingga 100, starting_after berisi ID dompet terakhir yang Anda miliki, dan has_more menunjukkan apakah masih ada lagi.
# By your reference
curl "https://cryptomerchant.online/api/v1/sticky-wallets?reference=user-1042" \
-H "Authorization: Bearer $CM_SECRET_KEY"
# By id
curl https://cryptomerchant.online/api/v1/sticky-wallets/sw_8Kd2pQx7Vb1mNc3T \
-H "Authorization: Bearer $CM_SECRET_KEY"
# All of them, 50 at a time
curl "https://cryptomerchant.online/api/v1/sticky-wallets?limit=50&starting_after=sw_8Kd2pQx7Vb1mNc3T" \
-H "Authorization: Bearer $CM_SECRET_KEY"{
"object": "list",
"data": [ { "id": "sw_8Kd2pQx7Vb1mNc3T", "object": "sticky_wallet", … } ],
"has_more": false
}Daftar deposit
GET/deposits
Semua deposit ke dompet pelanggan Anda, dari yang terbaru. Filter berdasarkan sticky_wallet (ID dompet) dan status (pending, confirmed, atau dropped), lalu telusuri halaman dengan limit dan starting_after (ID deposit). Gunakan untuk mengejar ketertinggalan saat server Anda melewatkan webhook.
curl "https://cryptomerchant.online/api/v1/deposits?sticky_wallet=sw_8Kd2pQx7Vb1mNc3T&status=confirmed&limit=20" \
-H "Authorization: Bearer $CM_SECRET_KEY"Objek deposit
idstring- ID deposit. Gunakan untuk memastikan setiap deposit hanya ditambahkan sekali.
statusstringpending: terdeteksi di jaringan, menunggu konfirmasi.confirmed: final, dan sudah masuk ke saldo Anda.dropped: tidak pernah dikonfirmasi.sticky_walletobject- Dompet tujuan pengirimannya:
iddanreferenceAnda. coinobject- Koin dan jaringannya.
amountstring- Jumlah yang dikirim pelanggan, dalam koin tersebut.
feestring- Biaya, dalam koin tersebut.
net_amountstring- Jumlah yang masuk ke saldo Anda (jumlah dikurangi biaya), setelah dikonfirmasi.
amount_usdstring- Nilainya dalam dolar AS saat deposit masuk.
tx_hashstring- Hash transaksi;
explorer_urlmembukanya di block explorer.
{
"id": "cmvu1x9a0000l10u8k2f3h7q",
"object": "deposit",
"status": "confirmed",
"sticky_wallet": { "id": "sw_8Kd2pQx7Vb1mNc3T", "reference": "user-1042" },
"coin": { "id": "USDT.TRON", "symbol": "USDT", "network": "Tron" },
"address": "TXbajeGHq4Vb…",
"amount": "250",
"amount_usd": "250.00",
"fee": "2.5",
"net_amount": "247.5",
"from_address": "TQn9Y2khEsLJ…",
"tx_hash": "36423ec5…f00d4a",
"explorer_url": "https://tronscan.org/#/transaction/36423ec5…f00d4a",
"confirmations": 19,
"detected_at": "2026-10-29T18:31:02.000Z",
"confirmed_at": "2026-10-29T18:32:01.000Z"
}Webhook
Event deposit membawa objek deposit di data. Periksa tanda tangannya, seperti dijelaskan di Webhook, sebelum memercayainya.
deposit.pending- Deposit ke dompet tetap salah satu pelanggan Anda terdeteksi on-chain dan sedang menunggu konfirmasi.
deposit.confirmed- Deposit dompet tetap dikonfirmasi dan masuk ke saldo Anda setelah dipotong biaya: tambahkan saldo pelanggan tersebut sekarang.
deposit.dropped- Deposit dompet tetap yang terdeteksi tidak pernah dikonfirmasi (gagal atau dihapus dari chain).
import express from "express";
import { verifyWebhook } from "./verify-webhook.js"; // from the Webhooks page
import { db } from "./db.js"; // your database; table webhook_events as on the Webhooks page
const app = express();
app.post(
"/webhooks/crypto-merchant",
express.raw({ type: "application/json" }),
async (req, res) => {
let event;
try {
event = verifyWebhook(req.body, req.get("CM-Signature"), process.env.CM_WEBHOOK_SECRET);
} catch {
return res.sendStatus(400);
}
try {
// Save first: a repeat delivery has the same event.id and is ignored
await db.query(
"INSERT INTO webhook_events (id, type, payload) VALUES ($1, $2, $3) ON CONFLICT (id) DO NOTHING",
[event.id, event.type, event],
);
} catch {
return res.sendStatus(500); // not saved: we send it again later
}
res.sendStatus(200); // stored, so confirm it
processEvents().catch(console.error); // or run it from a background job
},
);
async function processEvents() {
const { rows } = await db.query(
"SELECT payload FROM webhook_events WHERE processed_at IS NULL ORDER BY received_at",
);
for (const { payload: event } of rows) {
const deposit = event.data;
if (event.type === "deposit.pending") {
// Optional: show "deposit on its way" to deposit.sticky_wallet.reference
}
if (event.type === "deposit.confirmed") {
// Credit once: creditCustomer must skip a deposit.id it has already credited
await creditCustomer({
customerId: deposit.sticky_wallet.reference,
depositId: deposit.id,
coin: deposit.coin.id, // e.g. "USDT.TRON"
amount: deposit.net_amount, // or deposit.amount to cover the fee yourself
txHash: deposit.tx_hash,
});
}
await db.query("UPDATE webhook_events SET processed_at = now() WHERE id = $1", [event.id]);
}
}Error
400invalid_request: ada field yang hilang atau salah; pesannya menyebutkan field mana.401unauthorized: kunci rahasia tidak ada atau tidak valid.403sticky_wallets_unavailable: dompet tetap belum diaktifkan untuk bisnis ini, atau penyiapannya belum selesai.404not_found: tidak ada dompet tetap dengan ID tersebut.
Praktik yang baik
- Tambahkan saldo pelanggan hanya saat menerima
deposit.confirmed, dan hanya sekali periddeposit: webhook dapat tiba lebih dari sekali. - Tentukan siapa yang menanggung biaya: tambahkan
net_amountuntuk membebankannya ke pelanggan, atauamountuntuk menanggungnya sendiri. - Referensi Anda adalah kuncinya: memanggil
POST /sticky-walletslagi selalu aman, jadi Anda tidak perlu menyimpan alamatnya. - Simpan kunci rahasia di server Anda. Jika bocor, cabut kunci tersebut di Developer dan buat yang baru.
- Jika endpoint Anda sempat mati, ambil daftar deposit
confirmedlalu tambahkan saldo untuk deposit yang belum Anda tangani. - Membuat saldo untuk pelanggan? Baca cara menambahkan isi saldo kripto ke akun pelanggan.