API compatível com a NOWPayments

Abrir no ChatGPTAbrir no Claude

Os caminhos, o cabeçalho x-api-key, os campos de requisição e resposta, os status e a assinatura IPN x-nowpayments-sig seguem a documentação da NOWPayments, então o código existente normalmente só precisa de uma nova URL base, uma nova API key e um novo IPN secret. Vindo de outro lugar? Veja a visão geral da migração.

Por baixo é uma cobrança comum da blockwallets: os endereços de recebimento são seus, a página de pagamento é o nosso checkout hospedado, e um pagamento só vale depois de confirmado na blockchain e conferido com um segundo nó. A seguir: três passos, depois o que cada API suporta e como ela difere da original — parâmetros que não implementamos retornam erro em vez de serem ignorados em silêncio.

Três passos

  1. Consiga uma conta de lojista (solicite na página inicial) e cadastre os seus domínios em “Domínios do site”, em “Desenvolvedores › Integração e chaves” no painel. As URLs de callback (ipn_callback_url) e de redirecionamento (success_url / cancel_url / redirect_url) precisam estar nesses domínios ou no domínio da sua URL de callback — uma chave vazada não consegue apontar webhooks para outro lugar.
  2. Gere credenciais compatíveis no painel do lojista, em “Desenvolvedores › Integração e chaves”, um conjunto para live e outro para test: a NOWPayments recebe uma API key + IPN secret, a Coinbase Commerce uma API key + webhook shared secret. Elas são exibidas uma única vez; guardamos apenas hashes / texto cifrado.
  3. Aponte o seu código para a URL base abaixo e use as novas chaves. Rode primeiro nas testnets com as credenciais de test e depois passe para live.
AntesDepoisCabeçalho de autenticaçãoAssinatura do webhook
https://api.nowpayments.io/v1https://blockwallets.io/nowpayments/v1x-api-keyx-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();

Endpoints suportados

EndpointObservações
GET /status{"message":"OK"}, sem necessidade de chave
GET /currencies · /merchant/coins · /full-currenciesMoedas que você pode aceitar agora (tickers abaixo); fixed_rate é ignorado
GET /min-amount · GET /estimateMínimos e estimativas; precificação apenas em USD (USDT / USDC contam 1:1)
POST /paymentCria um pagamento; retorna pay_address / pay_amount na hora (white-label)
POST /invoiceCria uma fatura (invoice); invoice_url é o nosso checkout hospedado, onde o cliente escolhe moeda e rede
POST /invoice-paymentEscolhe a moeda de uma fatura (invoice) e retorna o pagamento
GET /payment/:idStatus do pagamento
GET /payment/Lista: limit (1–500) / page / orderBy / dateFrom / dateTo / invoiceId; sortBy somente created_at
POST /authA lista só precisa de x-api-key, sem JWT; este retorna um token de preenchimento sem verificação para que o código “fazer login e depois listar” continue funcionando (e-mail / senha não são verificados)

Não disponíveis: payouts, conversões, subparceiros de custódia, assinaturas, update-merchant-estimate, pagamentos em moeda fiduciária. Esses caminhos retornam 404.

Callbacks IPN

Quando um pagamento chega a um status final, enviamos um POST para a ipn_callback_url informada na criação, com x-nowpayments-sig = HMAC-SHA512(IPN secret, o JSON ordenado recursivamente por chave) — exatamente o código de verificação da NOWPayments. O corpo que enviamos já é um JSON compacto e ordenado, então um HMAC sobre o corpo bruto também funciona (e é a escolha mais segura em PHP / Python, cuja recodificação de decimais muito pequenos pode diferir da do JS). Callbacks que falham são reenviados após 1 min, 5 min, 30 min, … — 8 tentativas no total.

Node.js
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_statusQuandoIPN enviado
waitingAguardando pagamento (inclusive uma fatura (invoice) sem moeda escolhida ainda)—
confirmingPagamento visto na blockchain, aguardando confirmações— (visível ao consultar)
finishedPago (inclusive com pagamento a mais; actually_paid é o que chegou)✓
partially_paidInsuficiente: o cliente ainda pode complementar no mesmo endereço antes de expirar (enviado uma vez no primeiro pagamento insuficiente), e de novo se ainda faltar na expiração✓
expiredExpirado sem pagamento✓
refundedVocê reembolsou o pagamento inteiro pelo painel e ele foi enviado— (visível ao consultar)

confirmed, sending e failed nunca aparecem: depois de confirmado vira finished e é creditado no seu saldo; nada é repassado.

Tickers das moedas

MoedaRedepay_currencynetworkMínimo
USDTTRONusdttrc20trx$1
USDTBNB Chainusdtbsc usdtbep20bsc$1
USDCBNB Chainusdcbsc usdcbep20bsc$1
USDTEthereumusdterc20eth$5
USDCEthereumusdc usdcerc20eth$5
USDCBaseusdcbasebase$1
USDTPolygonusdtmatic usdtpolygonmatic$1
USDCPolygonusdcmatic usdcpolygonmatic$1
USDTArbitrumusdtarbarbitrum$1
USDCArbitrumusdcarbarbitrum$1
USDTOptimismusdtopop$1
USDCOptimismusdcopop$1
USDTAvalancheusdtarc20 usdtavax / usdtavaxcavaxc$1
USDCAvalancheusdcarc20 usdcavax / usdcavaxcavaxc$1
USDTX Layerusdtxlayerxlayer$1
USDCX Layerusdcxlayerxlayer$1
USD1BNB Chainusd1bscbsc$1
FDUSDBNB Chainfdusdbscbsc$1
DAIEthereumdai daierc20eth$5
DAIArbitrumdaiarbarbitrum$1
DAIBasedaibasebase$1
BTCBitcoinbtcbtc$5
LTCLitecoinltcltc$1
DOGEDogecoindogedoge$1
BCHBitcoin Cashbchbch$1
TRXTRONtrxtrx$1
BNBBNB Chainbnbbsc bnbbsc$1
ETHEthereumetheth$5
ETHBaseethbasebase$1
ETHArbitrumetharbarbitrum$1
ETHOptimismethopop$1
POLPolygonmaticmainnet pol / polmainnet / maticmatic$1
AVAXAvalancheavaxc avaxavaxc$1
OKBX Layerokbxlayerxlayer$1
USDTSolanausdtsolsol$1
USDCSolanausdcsolsol$1
SOLSolanasolsol$1
USDTTONusdttonton$1
TONTONtonton$1

Diferenças em relação à NOWPayments

Modo de teste

Cobranças e pagamentos criados com credenciais de test rodam na testnet de cada rede e os webhooks deles são assinados com o IPN secret / shared secret de test — totalmente separados do live: uma chave de test não enxerga pagamentos live.

Todo o resto (checkout, confirmações, redes e mínimos, reembolsos) funciona como na documentação principal.