# API kompatibel NOWPayments

> Beralih dari NOWPayments ke blockwallets cukup dengan mengganti base URL dan kunci: endpoint yang didukung, callback dan tanda tangan IPN, ticker mata uang, dan perbedaannya.
>
> HTML: https://blockwallets.io/docs/nowpayments?lang=id · English: https://blockwallets.io/docs/nowpayments.md?lang=en

## API kompatibel NOWPayments

Path, header `x-api-key`, field permintaan dan respons, status, serta tanda tangan IPN `x-nowpayments-sig` mengikuti dokumentasi NOWPayments, sehingga kode yang ada biasanya hanya perlu base URL, API key, dan IPN secret baru. Datang dari tempat lain? Lihat [ringkasan migrasi](https://blockwallets.io/docs/migrate?lang=id).

Di baliknya adalah tagihan blockwallets biasa: alamat penerima milik Anda, halaman pembayaran adalah kasir yang kami host, dan pembayaran baru dihitung setelah terkonfirmasi di chain dan diperiksa silang dengan node kedua. Di bawah ini: tiga langkah, lalu apa yang didukung setiap API dan **apa bedanya dengan aslinya** — parameter yang tidak kami implementasikan mengembalikan error, bukan diabaikan diam-diam.

### Tiga langkah

- Dapatkan akun merchant ([ajukan di beranda](https://blockwallets.io/?lang=id#join)) dan tambahkan domain Anda di “Domain situs web” pada “Developer › Integrasi & kunci” di dasbor. URL callback (`ipn_callback_url`) dan URL pengalihan (`success_url` / `cancel_url` / `redirect_url`) harus berada di domain itu atau di domain URL callback Anda — kunci yang bocor tidak bisa mengarahkan webhook ke tempat lain.

- Buat kredensial kompatibel di dasbor merchant pada “Developer › Integrasi & kunci”, satu set untuk live dan satu untuk uji: NOWPayments mendapat **API key + IPN secret**, Coinbase Commerce mendapat **API key + webhook shared secret**. Semuanya ditampilkan sekali; kami hanya menyimpan hash / ciphertext.

- Arahkan kode Anda ke base URL di bawah dan pakai kunci baru. Jalankan dulu di testnet dengan kredensial uji, lalu beralih ke live.

| Sebelum | Sesudah | Header autentikasi | Tanda tangan webhook |
| --- | --- | --- | --- |
| `https://api.nowpayments.io/v1` | `https://blockwallets.io/nowpayments/v1` | `x-api-key` | `x-nowpayments-sig` (HMAC-SHA512) |

### NOWPayments

```javascript
- const NP = "https://api.nowpayments.io/v1";
+ const NP = "https://blockwallets.io/nowpayments/v1";

const res = await fetch(`${NP}/payment`, {
  method: "POST",
  headers: { "x-api-key": process.env.NOWPAYMENTS_API_KEY, "content-type": "application/json" },
  body: JSON.stringify({
    price_amount: 49.9, price_currency: "usd", pay_currency: "usdttrc20",
    order_id: "A-1001", order_description: "Pro plan",
    ipn_callback_url: "https://shop.example/ipn/nowpayments",
  }),
});
const { payment_id, pay_address, pay_amount } = await res.json();
```

#### Endpoint yang didukung

| Endpoint | Catatan |
| --- | --- |
| `GET /status` | `{"message":"OK"}`, tanpa kunci |
| `GET /currencies` · `/merchant/coins` · `/full-currencies` | Koin yang bisa Anda terima saat ini (ticker di bawah); `fixed_rate` diabaikan |
| `GET /min-amount` · `GET /estimate` | Minimum dan estimasi; hanya harga USD (USDT / USDC dihitung 1:1) |
| `POST /payment` | Membuat pembayaran; langsung mengembalikan `pay_address` / `pay_amount` (white-label) |
| `POST /invoice` | Membuat invoice; `invoice_url` adalah kasir yang kami host tempat pelanggan memilih koin dan jaringan |
| `POST /invoice-payment` | Memilih koin untuk sebuah invoice, mengembalikan pembayarannya |
| `GET /payment/:id` | Status pembayaran |
| `GET /payment/` | Daftar: `limit` (1–500) / `page` / `orderBy` / `dateFrom` / `dateTo` / `invoiceId`; `sortBy` hanya `created_at` |
| `POST /auth` | Daftar hanya butuh `x-api-key`, tanpa JWT; endpoint ini mengembalikan token placeholder yang tidak diperiksa agar kode “login lalu tampilkan daftar” tetap berjalan (email / password tidak diperiksa) |

Tidak tersedia: payout, konversi, sub-partner kustodian, langganan, `update-merchant-estimate`, pembayaran fiat. Path tersebut mengembalikan 404.

#### Callback IPN

Saat pembayaran mencapai status akhir, kami mengirim POST ke `ipn_callback_url` yang diberikan saat pembuatan, dengan `x-nowpayments-sig` = HMAC-SHA512(IPN secret, JSON yang diurutkan berdasarkan key secara rekursif) — persis kode verifikasi NOWPayments. Body yang kami kirim sudah berupa JSON ringkas yang terurut, jadi HMAC atas body mentah juga berfungsi (dan paling aman di PHP / Python, yang encode ulang desimal sangat kecil bisa berbeda dari JS). Callback yang gagal dicoba lagi setelah 1 mnt, 5 mnt, 30 mnt, … — total 8 percobaan.

```nodejs
import crypto from "node:crypto";

// Same as the NOWPayments docs (our body is already sorted, so hashing the raw body works too)
function sortObject(obj) {
  return Object.keys(obj).sort().reduce((r, k) => {
    r[k] = obj[k] && typeof obj[k] === "object" ? sortObject(obj[k]) : obj[k];
    return r;
  }, {});
}
function verifyIpn(params, sig, ipnSecret) {
  const hmac = crypto.createHmac("sha512", ipnSecret).update(JSON.stringify(sortObject(params))).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(hmac), Buffer.from(sig || ""));
}
// verifyIpn(req.body, req.headers["x-nowpayments-sig"], process.env.NOWPAYMENTS_IPN_SECRET)
```

```php
$raw = file_get_contents('php://input');
$data = json_decode($raw, true);
tksort($data);  // the recursive ksort from the NOWPayments docs
$hmac = hash_hmac('sha512', json_encode($data, JSON_UNESCAPED_SLASHES), trim($ipnSecret));
$ok = hash_equals($hmac, $_SERVER['HTTP_X_NOWPAYMENTS_SIG'] ?? '');
```

| payment_status | Kapan | IPN yang dikirim |
| --- | --- | --- |
| `waiting` | Menunggu pembayaran (juga invoice yang belum dipilih koinnya) | — |
| `confirming` | Pembayaran terlihat di chain, menunggu konfirmasi | — (terlihat saat Anda melakukan kueri) |
| `finished` | Lunas (termasuk kelebihan bayar; `actually_paid` adalah jumlah yang masuk) | ✓ |
| `partially_paid` | Kurang: pelanggan masih bisa menambah ke alamat yang sama sebelum kedaluwarsa (dikirim sekali saat pembayaran kurang pertama), dan lagi jika masih kurang saat kedaluwarsa | ✓ |
| `expired` | Kedaluwarsa tanpa pembayaran | ✓ |
| `refunded` | Anda me-refund seluruh pembayaran dari dasbor dan sudah terkirim | — (terlihat saat Anda melakukan kueri) |

`confirmed`, `sending`, dan `failed` tidak pernah muncul: setelah terkonfirmasi statusnya `finished` dan dikreditkan ke saldo Anda; tidak ada yang diteruskan.

#### Ticker mata uang

| Koin | Jaringan | pay_currency | network | Minimum |
| --- | --- | --- | --- | --- |
| USDT | TRON | `usdttrc20` | `trx` | $1 |
| USDT | BNB Chain | `usdtbsc` usdtbep20 | `bsc` | $1 |
| USDC | BNB Chain | `usdcbsc` usdcbep20 | `bsc` | $1 |
| USDT | Ethereum | `usdterc20` | `eth` | $5 |
| USDC | Ethereum | `usdc` usdcerc20 | `eth` | $5 |
| USDC | Base | `usdcbase` | `base` | $1 |
| USDT | Polygon | `usdtmatic` usdtpolygon | `matic` | $1 |
| USDC | Polygon | `usdcmatic` usdcpolygon | `matic` | $1 |
| USDT | Arbitrum | `usdtarb` | `arbitrum` | $1 |
| USDC | Arbitrum | `usdcarb` | `arbitrum` | $1 |
| USDT | Optimism | `usdtop` | `op` | $1 |
| USDC | Optimism | `usdcop` | `op` | $1 |
| USDT | Avalanche | `usdtarc20` usdtavax / usdtavaxc | `avaxc` | $1 |
| USDC | Avalanche | `usdcarc20` usdcavax / usdcavaxc | `avaxc` | $1 |
| USDT | X Layer | `usdtxlayer` | `xlayer` | $1 |
| USDC | X Layer | `usdcxlayer` | `xlayer` | $1 |
| USD1 | BNB Chain | `usd1bsc` | `bsc` | $1 |
| FDUSD | BNB Chain | `fdusdbsc` | `bsc` | $1 |
| DAI | Ethereum | `dai` daierc20 | `eth` | $5 |
| DAI | Arbitrum | `daiarb` | `arbitrum` | $1 |
| DAI | Base | `daibase` | `base` | $1 |
| BTC | Bitcoin | `btc` | `btc` | $5 |
| LTC | Litecoin | `ltc` | `ltc` | $1 |
| DOGE | Dogecoin | `doge` | `doge` | $1 |
| BCH | Bitcoin Cash | `bch` | `bch` | $1 |
| TRX | TRON | `trx` | `trx` | $1 |
| BNB | BNB Chain | `bnbbsc` bnb | `bsc` | $1 |
| ETH | Ethereum | `eth` | `eth` | $5 |
| ETH | Base | `ethbase` | `base` | $1 |
| ETH | Arbitrum | `etharb` | `arbitrum` | $1 |
| ETH | Optimism | `ethop` | `op` | $1 |
| POL | Polygon | `maticmainnet` pol / polmainnet / matic | `matic` | $1 |
| AVAX | Avalanche | `avaxc` avax | `avaxc` | $1 |
| OKB | X Layer | `okbxlayer` | `xlayer` | $1 |
| USDT | Solana | `usdtsol` | `sol` | $1 |
| USDC | Solana | `usdcsol` | `sol` | $1 |
| SOL | Solana | `sol` | `sol` | $1 |
| USDT | TON | `usdtton` | `ton` | $1 |
| TON | TON | `ton` | `ton` | $1 |

#### Perbedaan dari NOWPayments

- `price_currency` hanya `usd` (plus `usdt` / `usdc` pada 1:1); fiat lain mengembalikan 400.

- `pay_amount` (jumlah kripto tetap), `payout_address` / `payout_currency` / `payout_extra_id`, dan `customer_email` tidak didukung dan mengembalikan 400.

- `is_fixed_rate` diterima tetapi tidak berpengaruh: kami selalu mengunci kurs (BTC / LTC dll. pada median beberapa exchange, selama 30 menit). Jika `is_fee_paid_by_user` true, biaya platform ditambahkan ke `pay_amount` (biaya platform 1%, makin rendah pada volume lebih tinggi; lihat [harga](https://blockwallets.io/pricing?lang=id)).

- Pembayaran berlaku hingga 12 jam (NOWPayments: 7 hari). `partially_paid_url` disimpan dan dikembalikan apa adanya, tetapi kasir tidak mengalihkan ke sana.

- `payment_id` adalah angka 10 digit; untuk invoice yang dibuat dengan `/invoice`, `payment_id` pembayarannya sama dengan `id` invoice, dan satu invoice punya tepat satu pembayaran (tanpa setoran ulang `parent_payment_id`).

- Hanya IPN berstatus akhir dan `partially_paid` yang dikirim (tabel di atas), tanpa `waiting` / `confirming`; `fee.serviceFee` adalah biaya platform (jumlah yang diterima × tarif saat tagihan dibuat, 1% standar), biaya lainnya 0.

### Mode uji

Charge dan pembayaran yang dibuat dengan kredensial uji berjalan di testnet tiap chain dan webhook-nya ditandatangani dengan IPN secret / shared secret uji — sepenuhnya terpisah dari live: kunci uji tidak bisa melihat pembayaran live.

Sisanya (kasir, konfirmasi, jaringan dan minimum, refund) bekerja seperti di [dokumentasi utama](https://blockwallets.io/docs/cryptomus?lang=id).
