# API tương thích Coinbase Commerce

> Chuyển từ Coinbase Commerce sang blockwallets chỉ bằng cách đổi URL gốc của SDK và khóa: các endpoint charge được hỗ trợ, webhook và chữ ký, cùng các điểm khác biệt.
>
> HTML: https://blockwallets.io/docs/coinbase-commerce?lang=vi · English: https://blockwallets.io/docs/coinbase-commerce.md?lang=en

## API tương thích Coinbase Commerce

Các endpoint charge, header `X-CC-Api-Key`, đối tượng charge và webhook ký bằng `X-CC-Webhook-Signature` đều theo tài liệu của Coinbase Commerce, nên các SDK chính thức hoạt động sau khi đổi một dòng. Coinbase Commerce đã ngừng phục vụ người bán ngoài Hoa Kỳ và Singapore từ ngày 2026-03-31. Đến từ nơi khác? Xem [tổng quan chuyển đổi](https://blockwallets.io/docs/migrate?lang=vi).

Bên dưới đó là một hóa đơn blockwallets bình thường: địa chỉ nhận tiền là của bạn, trang thanh toán là trang thanh toán do chúng tôi lưu trữ, và một khoản thanh toán chỉ được tính khi đã được xác nhận trên chuỗi và đối chiếu với node thứ hai. Phần dưới gồm: ba bước, rồi từng API hỗ trợ gì và **khác bản gốc ở đâu** — tham số chúng tôi không triển khai sẽ trả về lỗi chứ không bị bỏ qua âm thầm.

### Ba bước

- Có tài khoản người bán ([đăng ký dùng ở trang chủ](https://blockwallets.io/?lang=vi#join)) và thêm tên miền của bạn trong “Tên miền website” ở “Nhà phát triển › Tích hợp & khóa” trong trang quản trị. URL callback (`ipn_callback_url`) và URL chuyển hướng (`success_url` / `cancel_url` / `redirect_url`) phải thuộc các tên miền đó hoặc tên miền của URL callback của bạn — khóa bị lộ cũng không thể trỏ webhook sang nơi khác.

- Tạo thông tin xác thực tương thích trong trang quản trị ở mục “Nhà phát triển › Tích hợp & khóa”, một bộ cho live và một bộ cho thử nghiệm: NOWPayments dùng **API key + IPN secret**, Coinbase Commerce dùng **API key + webhook shared secret**. Chúng chỉ hiển thị một lần; chúng tôi chỉ lưu giá trị băm / bản mã hóa.

- Trỏ code của bạn đến URL gốc bên dưới và dùng khóa mới. Chạy thử trên testnet bằng thông tin xác thực thử nghiệm trước, rồi mới chuyển sang live.

| Trước | Sau | Header xác thực | Chữ ký webhook |
| --- | --- | --- | --- |
| `https://api.commerce.coinbase.com` | `https://blockwallets.io/coinbase/` | `X-CC-Api-Key` | `X-CC-Webhook-Signature` (HMAC-SHA256) |

### Coinbase Commerce

Mọi SDK chính thức đều nhận một URL gốc — chỉ đổi một dòng (chú ý dấu `/` ở cuối):

```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", …}], …}}
```

#### Endpoint được hỗ trợ

| Endpoint | Ghi chú |
| --- | --- |
| `POST /charges` | Tạo charge; `hosted_url` là trang thanh toán do chúng tôi lưu trữ; có hiệu lực 1 giờ |
| `GET /charges/:code_or_id` | Tra cứu theo mã 8 ký tự hoặc id |
| `GET /charges` | Danh sách: `limit` (≤100) / `starting_after` / `ending_before` / `order`, với cùng đối tượng `pagination` |
| `POST /charges/:code_or_id/cancel` | Hủy charge chưa thấy khoản thanh toán nào |

Không có: `/charges/:code/resolve` (400 — hãy xử lý charge trả thiếu trong trang quản trị), `/checkouts`, `/events`, `/invoices` (404).

#### Webhook

Webhook của Coinbase ở cấp tài khoản, và của chúng tôi cũng vậy: chúng đến **URL callback** đặt trong trang quản trị của bạn (charge tạo bằng thông tin xác thực thử nghiệm đến URL callback thử nghiệm). Nội dung là `{id, scheduled_for, attempt_number, event: {id, type, api_version, created_at, data}}` của Coinbase, với charge đầy đủ trong `data`; `X-CC-Webhook-Signature` = HMAC-SHA256(shared secret, nội dung thô), nên `Webhook.verifyEventBody` của các SDK dùng được nguyên trạng. Khi thử lại, `event.id` giữ nguyên còn `attempt_number` tăng lên — hãy loại trùng theo `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)
```

| Sự kiện | Khi nào | Mục cuối trong timeline |
| --- | --- | --- |
| `charge:confirmed` | Đã thanh toán (được xác nhận trên chuỗi và đối chiếu; trả dư vẫn tính) | `COMPLETED` |
| `charge:failed` | Hết hạn chưa thanh toán / bạn đã hủy / hết hạn khi trả thiếu | `EXPIRED` / `CANCELED` / `UNRESOLVED` (context `UNDERPAID`) |

Khi truy vấn bạn còn thấy `NEW` (chờ thanh toán) và `PENDING` (đã thấy thanh toán trên chuỗi, đang xác nhận). **Hãy giao hàng khi nhận `charge:confirmed`**: chúng tôi không gửi `charge:created`, `charge:pending`, `charge:delayed` hay `charge:resolved`.

#### Khác biệt so với Coinbase Commerce

- `pricing_type` phải là `fixed_price`; `local_price.currency` phải là USD (USDC / USDT theo 1:1). `no_price` và tiền pháp định khác trả về 400.

- Địa chỉ xuất hiện khi khách chọn coin và mạng tại trang thanh toán: `addresses` chỉ chứa mạng đó, `pricing` chỉ có `local` cùng `settlement` sau khi đã chọn; không có `exchange_rates`, `checkout` hay các trường thương hiệu.

- `metadata` được lưu và trả lại nguyên vẹn (tối đa 4 KB).

- Hoàn tiền không xuất hiện trong timeline; hãy xem trong trang quản trị.

### Chế độ thử nghiệm

Charge và thanh toán tạo bằng thông tin xác thực thử nghiệm chạy trên testnet của từng chuỗi và webhook của chúng được ký bằng IPN secret / shared secret thử nghiệm — tách biệt hoàn toàn với live: khóa thử nghiệm không thấy được các khoản thanh toán live.

Mọi thứ còn lại (trang thanh toán, xác nhận, mạng và mức tối thiểu, hoàn tiền) hoạt động như trong [tài liệu chính](https://blockwallets.io/docs/cryptomus?lang=vi).
