BitPay Integration

We design and develop full-cycle blockchain solutions: from smart contract architecture to launching DeFi protocols, NFT marketplaces and crypto exchanges. Security audits, tokenomics, integration with existing infrastructure.
Showing 1 of 1 servicesAll 1306 services
BitPay Integration
Simple
~2-3 business days
FAQ
Blockchain Development Services
Blockchain Development Stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1217
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    852
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1046
  • image_logo-advance_0.png
    B2B Advance company logo design
    561
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    823

BitPay Integration

BitPay is one of the oldest crypto payment processors, launched in 2011. Today it supports BTC, ETH, USDC, USDT on several networks (Ethereum, Polygon, Arbitrum, Base) with automatic conversion to fiat. For businesses wanting to accept crypto without their own infrastructure and with ready legal documentation — a reasonable choice.

The API works via invoices (invoices): your backend creates an invoice on BitPay, gets a URL to redirect the user, BitPay accepts payment and notifies your webhook.

API Authentication

BitPay uses a non-standard authentication scheme based on ECDSA signatures. The client generates an ECDSA keypair, the public key is registered as a "token" on BitPay. Each request is signed with the private key.

const BitPaySDK = require('bitpay-sdk');
const fs = require('fs');

// Generate keys and get token (one time)
async function setupBitPay() {
    const client = new BitPaySDK.Client(
        null,  // config file
        BitPaySDK.Env.Prod,  // or Env.Test for testnet
        fs.readFileSync('./private.key', 'utf8')  // ECDSA private key
    );
    
    // Token from BitPay Dashboard → API Tokens
    await client.authorizeClient('your-pairing-code');
    return client;
}

For most integrations it's easier to use the official BitPay SDK (Node.js, PHP, Python, Ruby, Java) — it encapsulates request signing.

Creating an Invoice

const BitPaySDK = require('bitpay-sdk');

async function createInvoice(orderId, amount, currency = 'USD') {
    const invoice = new BitPaySDK.Models.Invoice(amount, currency);
    
    invoice.orderId = orderId;
    invoice.notificationUrl = `https://yourapp.com/webhooks/bitpay`;
    invoice.redirectUrl = `https://yourapp.com/orders/${orderId}/success`;
    invoice.closeUrl = `https://yourapp.com/orders/${orderId}/cancel`;
    
    // Metadata for reconciliation
    invoice.buyer = new BitPaySDK.Models.Buyer();
    invoice.buyer.email = customerEmail;
    
    // Optional: accept only specific coins
    // invoice.paymentCurrencies = ['BTC', 'USDC'];
    
    const created = await client.createInvoice(invoice);
    return {
        invoiceId: created.id,
        paymentUrl: created.url,  // redirect user
        expirationTime: created.expirationTime
    };
}

Invoice is valid for 15 minutes (by default) — user must pay within this period. Amount in USD is fixed at BitPay's rate at time of invoice creation.

Webhook Processing

BitPay sends IPN (Instant Payment Notification) to notificationUrl. Critically: verify invoice status via API, don't just trust webhook data.

const express = require('express');
const router = express.Router();

router.post('/webhooks/bitpay', async (req, res) => {
    const { id: invoiceId, status } = req.body.data || {};
    
    if (!invoiceId) {
        return res.status(400).json({ error: 'Missing invoice ID' });
    }
    
    // IMPORTANT: verify via API, don't trust webhook body
    const invoice = await client.getInvoice(invoiceId);
    
    switch (invoice.status) {
        case 'paid':
            // Paid, but waiting for confirmations
            await updateOrderStatus(invoice.orderId, 'paid_unconfirmed');
            break;
        case 'confirmed':
            // Enough confirmations (usually 1 for most coins)
            await updateOrderStatus(invoice.orderId, 'confirmed');
            break;
        case 'complete':
            // All confirmations received, funds credited
            await fulfillOrder(invoice.orderId);
            break;
        case 'expired':
            await updateOrderStatus(invoice.orderId, 'expired');
            break;
        case 'invalid':
            // Underpayment or other error
            await handleInvalidPayment(invoice.orderId, invoice);
            break;
    }
    
    res.json({ success: true });
});

Status chain: newpaidconfirmedcomplete. Use confirmed or complete for fulfillment depending on risk tolerance. complete is safest but has longer delay.

Refunds

BitPay requires a return address — request it from the user at payment time or when initiating refund.

async function createRefund(invoiceId, amount, currency) {
    const refund = new BitPaySDK.Models.Refund();
    refund.invoiceId = invoiceId;
    refund.amount = amount;
    refund.currency = currency;  // refund currency
    
    const created = await client.createRefund(refund);
    // BitPay will send email to user requesting address
    return created;
}

Typical Integration Issues

Webhook doesn't arrive. BitPay requires HTTPS with valid certificate on notificationUrl. Localhost unreachable — for development use ngrok or BitPay Testnet with public URL.

Duplicate webhooks. BitPay can send multiple notifications about same status (retry on timeout). Use invoiceId as idempotency key: INSERT ... ON CONFLICT (invoice_id, status) DO NOTHING.

Partial payment. If user paid less — status is invalid. BitPay automatically returns underpayment if buyer email is present.

Timezone in expirationTime. Field returns as Unix timestamp in milliseconds. new Date(invoice.expirationTime) — don't forget ms, not seconds.

Testing

BitPay provides Testnet environment (BitPaySDK.Env.Test) with test Bitcoin. Create invoice, pay with testnet wallet — whole flow without real money. Pairing code for test environment created separately in dashboard.

Integration Process

Registration → API token creation → SDK integration in backend → webhook endpoint → Testnet testing → production pairing.

Timeline 2-3 days: 1 day on SDK integration and invoice creation, 1 day on webhook + status machine, 1 day on testing and edge cases (expired invoice, partial payment, webhook retry).