Loading...
Loading...
Docs / Migration guide / Coinbase Commerce
Use this page to run a controlled provider cutover: confirm the settlement model change, map the charge contract to Payvra payments, replace the webhook handler, and move traffic only after the sandbox path is repeatable.
The safe rollout: keep existing Coinbase Commerce charges draining, point new payment creation at Payvra in sandbox, prove the signed webhook path, and then swap only the credential prefix when you promote to live.
What to prove before cutover
Settlement independence
Auto-conversion coverage
Cutover reversibility
Cutover facts
Primary naming change
Auth change
X-CC-Api-Key headers to test/live Payvra secret keys.Settlement change
Promotion rule
Coinbase Commerce and Payvra both process crypto payments, but the settlement and ecosystem dependency are different. Coinbase Commerce ties merchants to the Coinbase platform for settlement and fund management. Payvra operates independently with direct wallet settlement on any chain.
Treat this migration as a settlement-model upgrade, not just an endpoint rename. You are replacing the charge lifecycle, the webhook contract, and the settlement assumptions your reconciliation depends on.
Ecosystem independence
Auto-conversion on all chains
Dedicated support
Active development
| Coinbase Commerce | Maps to | Payvra | Notes |
|---|---|---|---|
POST /charges | POST /v1/payments | Replace `pricing_type` + `local_price` with `amount` + `currency`. Payvra returns a `checkoutUrl` directly. | |
GET /charges/{id} | GET /v1/payments/{id} | Same read path with richer settlement, conversion, and fee detail. | |
GET /charges | GET /v1/payments | Payvra adds cursor pagination, date-range, and status filters. | |
POST /checkouts | POST /v1/payment-links | Coinbase Commerce checkouts become Payvra payment links with the same reusable-link behavior. | |
GET /checkouts/{id} | GET /v1/payment-links/{id} | Same read pattern. | |
GET /events | - - | Payvra delivers events as signed webhooks. The webhook dashboard replaces event polling. | |
- - | POST /v1/refunds | Payvra supports API refunds. Coinbase Commerce requires manual refunds through the dashboard. | |
- - | POST /v1/withdrawals | On-demand withdrawals to any wallet. Coinbase Commerce settles only to a linked Coinbase account. |
Create a payment
Coinbase Commerce
// Coinbase Commerceconst response = await fetch("https://api.commerce.coinbase.com/charges", { method: "POST", headers: { "X-CC-Api-Key": "YOUR_COINBASE_KEY", "X-CC-Version": "2018-03-22", "Content-Type": "application/json", }, body: JSON.stringify({ name: "Order #123", description: "Premium subscription", pricing_type: "fixed_price", local_price: { amount: "49.99", currency: "USD" }, redirect_url: "https://yoursite.com/success", cancel_url: "https://yoursite.com/cancel", }),});const { data } = await response.json();// Redirect to: data.hosted_urlPayvra
// Payvraimport Payvra from "payvra";const payvraSecretKey = process.env.PAYVRA_SECRET_KEY;if (!payvraSecretKey) { throw new Error("Set PAYVRA_SECRET_KEY before running this example.");}const payvra = new Payvra(payvraSecretKey);const payment = await payvra.payments.create({ amount: "49.99", currency: "USDC", metadata: { orderId: "order_123" },});// Redirect to: payment.checkoutUrlVerify webhooks
Coinbase Commerce webhook
// Coinbase Commerce webhook handlerapp.post("/webhooks", (req, res) => { const signature = req.headers["x-cc-webhook-signature"]; const expected = crypto .createHmac("sha256", WEBHOOK_SECRET) .update(req.rawBody) .digest("hex"); if (signature !== expected) { return res.status(401).send("Invalid"); } const { event } = req.body; if (event.type === "charge:completed") { // Mark order paid, event.data.metadata.order_id } res.sendStatus(200);});Payvra webhook
// Payvra webhook handlerapp.post("/webhooks", (req, res) => { const signature = req.headers["webhook-signature"]; const timestamp = req.headers["webhook-timestamp"]; const webhookId = req.headers["webhook-id"]; const signedContent = `${webhookId}.${timestamp}.${req.rawBody}`; const expected = crypto .createHmac("sha256", WEBHOOK_SECRET) .update(signedContent) .digest("base64"); if (signature !== `v1,${expected}`) { return res.status(401).send("Invalid"); } const { type, data } = req.body; if (type === "payment.completed") { // Mark order paid, data.metadata.orderId } res.sendStatus(200);});charge: prefix. Payvra uses typed payment. events so your handler can branch on the event name directly.| Coinbase Commerce event | Maps to | Payvra | Notes |
|---|---|---|---|
Event charge:created | Webhook payment.created | Payment created and awaiting deposit. | |
Event charge:pending | Webhook payment.confirming | Deposit detected, waiting for confirmations. | |
Event charge:confirmed | Webhook payment.confirmed | Payment confirmed on-chain. | |
Event charge:completed | Webhook payment.completed | Payment settled and completed. | |
Event charge:failed | Webhook payment.failed | Payment failed. | |
Event charge:delayed | Webhook payment.confirming | Coinbase delayed status maps to confirming with extended confirmation tracking. | |
Event charge:resolved | Webhook payment.completed | Manual resolution maps to completed after operator review. |
Create sandbox credentials and keep live traffic where it is
sk_test_... and leave existing Coinbase Commerce charges running to completion. The first milestone is proving the new Payvra path, not forcing an all-at-once cutover.Install the Payvra SDK and replace charge creation
local_price.amount to amount, local_price.currency to currency, and metadata carries over directly.npm install payvraReplace the webhook handler before trusting paid-state updates
Run one full sandbox order to completion
Promote to live by swapping only the credential prefix
Can I run both providers in parallel?
Do I still need a Coinbase account?
What happens to auto-conversion?
What changes for webhook handling?
Start in sandbox, prove the signed webhook path, and only then shift live traffic. The migration stays reversible if you treat it as a controlled cutover instead of a same-day rewrite.