API compatible con Coinbase Commerce

Abrir en ChatGPTAbrir en Claude

Los endpoints de charges, la cabecera X-CC-Api-Key, el objeto charge y los webhooks firmados con X-CC-Webhook-Signature siguen la documentación de Coinbase Commerce, así que los SDK oficiales funcionan tras cambiar una sola línea. Coinbase Commerce dejó de dar servicio a comercios fuera de EE. UU. y Singapur el 2026-03-31. ¿Vienes de otra pasarela? Consulta el resumen de migración.

Por debajo es una factura normal de blockwallets: las direcciones de cobro son tuyas, la página de pago es nuestra caja alojada, y un pago solo cuenta cuando está confirmado en la cadena y contrastado con un segundo nodo. A continuación: tres pasos y después qué admite cada API y en qué se diferencia de la original: los parámetros que no implementamos devuelven un error en lugar de ignorarse en silencio.

Tres pasos

  1. Consigue una cuenta de comercio (solicítala en la página de inicio) y añade tus dominios en “Dominios del sitio web”, en “Desarrolladores › Integración y claves” del panel. Las URL de callback (ipn_callback_url) y de redirección (success_url / cancel_url / redirect_url) deben estar en esos dominios o en el dominio de tu URL de callback: una clave filtrada no puede apuntar los webhooks a otro sitio.
  2. Genera credenciales compatibles en el panel del comercio, en “Desarrolladores › Integración y claves”, un juego para live y otro para test: NOWPayments recibe una API key + IPN secret, Coinbase Commerce una API key + webhook shared secret. Se muestran una sola vez; nosotros solo guardamos hashes / texto cifrado.
  3. Apunta tu código a la URL base de abajo y usa las nuevas claves. Pruébalo primero en testnets con las credenciales de test y después pasa a live.
AntesDespuésCabecera de autenticaciónFirma del webhook
https://api.commerce.coinbase.comhttps://blockwallets.io/coinbase/X-CC-Api-KeyX-CC-Webhook-Signature (HMAC-SHA256)

Coinbase Commerce

Todos los SDK oficiales aceptan una URL base: cambia una línea (cuidado con la / final):

SDK
// Node(coinbase-commerce-node)
const { Client } = require("coinbase-commerce-node");
- Client.init(process.env.COINBASE_COMMERCE_API_KEY);
+ Client.init(process.env.COINBASE_COMMERCE_API_KEY, "https://blockwallets.io/coinbase/");

# Python(coinbase-commerce)
- client = Client(api_key=API_KEY)
+ client = Client(api_key=API_KEY, base_api_uri="https://blockwallets.io/coinbase/")

// PHP(coinbase/coinbase-commerce)
- ApiClient::init($apiKey);
+ ApiClient::init($apiKey, 'https://blockwallets.io/coinbase/');
curl
curl -X POST https://blockwallets.io/coinbase/charges \
  -H "X-CC-Api-Key: $COINBASE_COMMERCE_API_KEY" -H "X-CC-Version: 2018-03-22" \
  -H "content-type: application/json" \
  -d '{"name":"Order #12345","description":"Pro plan","pricing_type":"fixed_price",
       "local_price":{"amount":"100.00","currency":"USD"},
       "redirect_url":"https://shop.example/success","cancel_url":"https://shop.example/cancel",
       "metadata":{"order_id":"12345"}}'
# → 201 {"data": {"id": "…", "code": "7C7V5ECK", "hosted_url": "https://blockwallets.io/pay/inv_…", "timeline": [{"status": "NEW", …}], …}}

Endpoints admitidos

EndpointNotas
POST /chargesCrea un cargo (charge); hosted_url es nuestra caja alojada; válido durante 1 hora
GET /charges/:code_or_idBúsqueda por código de 8 caracteres o por id
GET /chargesListado: limit (≤100) / starting_after / ending_before / order, con el mismo objeto pagination
POST /charges/:code_or_id/cancelCancela un cargo (charge) sin ningún pago visto todavía

No disponibles: /charges/:code/resolve (400: gestiona los cargos pagados de menos en el panel), /checkouts, /events, /invoices (404).

Webhooks

Los webhooks de Coinbase son a nivel de cuenta, y los nuestros también: van a la URL de callback definida en tu panel (los cargos creados con credenciales de test van a la URL de callback de test). El cuerpo es el de Coinbase, {id, scheduled_for, attempt_number, event: {id, type, api_version, created_at, data}}, con el cargo completo en data; X-CC-Webhook-Signature = HMAC-SHA256(shared secret, cuerpo bruto), así que el Webhook.verifyEventBody de los SDK funciona tal cual. En los reintentos event.id se mantiene y attempt_number sube: deduplica por event.id.

Node.js
import crypto from "node:crypto";

// Same as the SDK's Webhook.verifySigHeader: HMAC-SHA256(shared secret, raw body)
function verifyWebhook(rawBody, sig, sharedSecret) {
  const hmac = crypto.createHmac("sha256", sharedSecret).update(rawBody, "utf8").digest("hex");
  return crypto.timingSafeEqual(Buffer.from(hmac), Buffer.from(sig || ""));
}
// verifyWebhook(rawBody, req.headers["x-cc-webhook-signature"], process.env.COINBASE_WEBHOOK_SECRET)
// or with the official SDK:Webhook.verifyEventBody(rawBody, signature, sharedSecret)
EventoCuándoÚltima entrada de la línea de tiempo
charge:confirmedPagado (confirmado en la cadena y contrastado; con pago de más también cuenta)COMPLETED
charge:failedCaducado sin pagar / cancelado por ti / caducado pagado de menosEXPIRED / CANCELED / UNRESOLVED (contexto UNDERPAID)

Al consultar también verás NEW (pendiente de pago) y PENDING (pago visto en la cadena, confirmando). Entrega el pedido con charge:confirmed: no enviamos charge:created, charge:pending, charge:delayed ni charge:resolved.

Diferencias con Coinbase Commerce

Modo de prueba

Los cargos y pagos creados con credenciales de test funcionan en la testnet de cada cadena y sus webhooks se firman con el IPN secret / shared secret de test, totalmente separados de live: una clave de test no puede ver pagos de live.

Todo lo demás (caja, confirmaciones, redes y mínimos, reembolsos) funciona como en la documentación principal.