API compatible Coinbase Commerce
Les endpoints charge, l’en-tête X-CC-Api-Key, l’objet charge et les webhooks signés avec X-CC-Webhook-Signature suivent la documentation de Coinbase Commerce : les SDK officiels fonctionnent donc après le changement d’une seule ligne. Coinbase Commerce a cessé de servir les marchands hors des États-Unis et de Singapour le 2026-03-31. Vous venez d’ailleurs ? Consultez l’aperçu de la migration.
Dessous, c’est une facture blockwallets ordinaire : les adresses de réception sont les vôtres, la page de paiement est notre caisse hébergée, et un paiement ne compte qu’une fois confirmé on-chain et recoupé avec un second nœud. Ci-dessous : trois étapes, puis ce que chaque API prend en charge et en quoi elle diffère de l’originale — les paramètres que nous n’implémentons pas renvoient une erreur au lieu d’être ignorés en silence.
Trois étapes
- Obtenez un compte marchand (demandez-le sur la page d’accueil) et ajoutez vos domaines dans « Domaines du site web », sous « Développeurs › Intégration et clés » du tableau de bord. Les URL de callback (
ipn_callback_url) et de redirection (success_url/cancel_url/redirect_url) doivent se trouver sur ces domaines ou sur le domaine de votre URL de callback — une clé divulguée ne peut pas rediriger les webhooks ailleurs. - Générez des identifiants compatibles dans le tableau de bord marchand, sous « Développeurs › Intégration et clés », un jeu pour live et un pour test : NOWPayments reçoit une API key + IPN secret, Coinbase Commerce une API key + webhook shared secret. Ils ne sont affichés qu’une fois ; nous ne conservons que des hashs / du texte chiffré.
- Pointez votre code vers l’URL de base ci-dessous et utilisez les nouvelles clés. Lancez d’abord sur les testnets avec les identifiants de test, puis passez en live.
| Avant | Après | En-tête d’authentification | Signature du webhook |
|---|---|---|---|
https://api.commerce.coinbase.com | https://blockwallets.io/coinbase/ | X-CC-Api-Key | X-CC-Webhook-Signature (HMAC-SHA256) |
Coinbase Commerce
Tous les SDK officiels acceptent une URL de base — changez une ligne (attention au / final) :
// 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 -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 pris en charge
| Endpoint | Remarques |
|---|---|
POST /charges | Crée une charge (charge) ; hosted_url est notre caisse hébergée ; valable 1 heure |
GET /charges/:code_or_id | Recherche par code de 8 caractères ou par id |
GET /charges | Liste : limit (≤100) / starting_after / ending_before / order, avec le même objet pagination |
POST /charges/:code_or_id/cancel | Annule une charge (charge) sans aucun paiement vu pour l’instant |
Non disponibles : /charges/:code/resolve (400 — traitez les charges sous-payées dans le tableau de bord), /checkouts, /events, /invoices (404).
Webhooks
Les webhooks de Coinbase sont au niveau du compte, et les nôtres aussi : ils vont à l’URL de callback définie dans votre tableau de bord (les charges créées avec des identifiants de test vont à l’URL de callback de test). Le corps est celui de Coinbase, {id, scheduled_for, attempt_number, event: {id, type, api_version, created_at, data}}, avec la charge complète dans data ; X-CC-Webhook-Signature = HMAC-SHA256(shared secret, corps brut), de sorte que le Webhook.verifyEventBody des SDK fonctionne tel quel. Lors des nouvelles tentatives, event.id reste identique et attempt_number augmente — dédoublonnez sur event.id.
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)| Événement | Quand | Dernière entrée de la timeline |
|---|---|---|
charge:confirmed | Payé (confirmé on-chain et recoupé ; le trop-perçu compte) | COMPLETED |
charge:failed | Expiré sans paiement / annulé par vous / expiré sous-payé | EXPIRED / CANCELED / UNRESOLVED (contexte UNDERPAID) |
Lors d’une requête, vous verrez aussi NEW (en attente de paiement) et PENDING (paiement vu on-chain, en cours de confirmation). Livrez sur charge:confirmed : nous n’envoyons ni charge:created, ni charge:pending, ni charge:delayed, ni charge:resolved.
Différences avec Coinbase Commerce
pricing_typedoit êtrefixed_price;local_price.currencydoit être USD (USDC / USDT à 1:1).no_priceet les autres monnaies fiat renvoient 400.- L’adresse apparaît une fois que le client a choisi crypto et réseau à la caisse :
addressesne contient que ce réseau,pricingseulementlocalplussettlementune fois le choix fait ; pas deexchange_rates, decheckoutni de champs de marque. metadataest stocké et renvoyé tel quel (jusqu’à 4 Ko).- Les remboursements n’apparaissent pas dans la timeline ; consultez-les dans le tableau de bord.
Mode test
Les charges et paiements créés avec des identifiants de test fonctionnent sur le testnet de chaque chaîne et leurs webhooks sont signés avec l’IPN secret / shared secret de test — totalement séparés du live : une clé de test ne voit pas les paiements live.
Tout le reste (caisse, confirmations, réseaux et minimums, remboursements) fonctionne comme dans la documentation principale.