# API compatível com a Coinbase Commerce

> Passe da Coinbase Commerce para a blockwallets trocando a URL base do SDK e as chaves: endpoints de charge compatíveis, webhooks e assinaturas, e diferenças.
>
> HTML: https://blockwallets.io/docs/coinbase-commerce?lang=pt · English: https://blockwallets.io/docs/coinbase-commerce.md?lang=en

## API compatível com a Coinbase Commerce

Os endpoints de charge, o cabeçalho `X-CC-Api-Key`, o objeto charge e os webhooks assinados com `X-CC-Webhook-Signature` seguem a documentação da Coinbase Commerce, então os SDKs oficiais funcionam depois de trocar uma linha. A Coinbase Commerce deixou de atender lojistas fora dos EUA e de Singapura em 2026-03-31. Vindo de outro lugar? Veja a [visão geral da migração](https://blockwallets.io/docs/migrate?lang=pt).

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

- Consiga uma conta de lojista ([solicite na página inicial](https://blockwallets.io/?lang=pt#join)) 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.

- 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.

- 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.

| Antes | Depois | Cabeçalho de autenticação | Assinatura do webhook |
| --- | --- | --- | --- |
| `https://api.commerce.coinbase.com` | `https://blockwallets.io/coinbase/` | `X-CC-Api-Key` | `X-CC-Webhook-Signature` (HMAC-SHA256) |

### Coinbase Commerce

Todos os SDKs oficiais aceitam uma URL base — mude uma linha (atenção à `/` 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 suportados

| Endpoint | Observações |
| --- | --- |
| `POST /charges` | Cria uma cobrança (charge); `hosted_url` é o nosso checkout hospedado; vale por 1 hora |
| `GET /charges/:code_or_id` | Busca por código de 8 caracteres ou por id |
| `GET /charges` | Lista: `limit` (≤100) / `starting_after` / `ending_before` / `order`, com o mesmo objeto `pagination` |
| `POST /charges/:code_or_id/cancel` | Cancela uma cobrança (charge) sem nenhum pagamento visto ainda |

Não disponíveis: `/charges/:code/resolve` (400 — trate cobranças pagas a menos no painel), `/checkouts`, `/events`, `/invoices` (404).

#### Webhooks

Os webhooks da Coinbase são no nível da conta, e os nossos também: vão para a **URL de callback** definida no seu painel (cobranças criadas com credenciais de test vão para a URL de callback de test). O corpo é o da Coinbase, `{id, scheduled_for, attempt_number, event: {id, type, api_version, created_at, data}}`, com a cobrança completa em `data`; `X-CC-Webhook-Signature` = HMAC-SHA256(shared secret, corpo bruto), então o `Webhook.verifyEventBody` dos SDKs funciona como está. Nas novas tentativas, `event.id` permanece o mesmo e `attempt_number` aumenta — deduplique por `event.id`.

```nodejs
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)
```

| Evento | Quando | Última entrada da linha do tempo |
| --- | --- | --- |
| `charge:confirmed` | Pago (confirmado na blockchain e conferido; pagamento a mais conta) | `COMPLETED` |
| `charge:failed` | Expirado sem pagamento / cancelado por você / expirado pago a menos | `EXPIRED` / `CANCELED` / `UNRESOLVED` (contexto `UNDERPAID`) |

Ao consultar você também verá `NEW` (aguardando pagamento) e `PENDING` (pagamento visto na blockchain, confirmando). **Entregue o pedido em `charge:confirmed`**: não enviamos `charge:created`, `charge:pending`, `charge:delayed` nem `charge:resolved`.

#### Diferenças em relação à Coinbase Commerce

- `pricing_type` precisa ser `fixed_price`; `local_price.currency` precisa ser USD (USDC / USDT a 1:1). `no_price` e outras moedas fiduciárias retornam 400.

- O endereço aparece quando o cliente escolhe moeda e rede no checkout: `addresses` contém apenas essa rede, `pricing` apenas `local` mais `settlement` depois da escolha; sem `exchange_rates`, `checkout` nem campos de marca.

- `metadata` é guardado e devolvido como está (até 4 KB).

- Reembolsos não aparecem na linha do tempo; veja-os no painel.

### 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](https://blockwallets.io/docs/cryptomus?lang=pt).
