Self-hosted, open-source Bitcoin payment processor. Accept on-chain BTC and Lightning with no fees or intermediaries via the Greenfield API.
- 01self-hosted BTC checkout
- 02no-KYC merchant payments
- 03Lightning + on-chain invoices
- 04BitPay API replacement
- 05ecommerce plugins
- # Self-host (Docker)
- git clone https://github.com/btcpayserver/btcpayserver-docker && cd btcpayserver-docker && ./btcpay-setup.sh
- # Or use the Node client
- pnpm add btcpay-greenfield-node-client
| Variable | Scope | Description |
|---|---|---|
| BTCPAY_BASE_URL | Server | Base URL of your BTCPay Server (e.g. https://btcpay.example.com). |
| BTCPAY_API_KEY | Server | Greenfield API key with invoice + store permissions. |
| BTCPAY_STORE_ID | Server | Target store ID inside your BTCPay Server instance. |
| BTCPAY_WEBHOOK_SECRET | Server | HMAC secret used to verify incoming webhook signatures. |
Use BTCPay Server's Greenfield API to accept Bitcoin and Lightning. Create an invoice with `POST {BTCPAY_BASE_URL}/api/v1/stores/{BTCPAY_STORE_ID}/invoices` using header `Authorization: token {BTCPAY_API_KEY}` and body `{ amount, currency, metadata, checkout: { redirectURL, defaultPaymentMethod: 'BTC-LN' } }`. Redirect the user to `invoice.checkoutLink`. Listen for `invoice.settled`/`invoice.processing` webhooks at your endpoint and verify the `BTCPay-Sig` HMAC against `BTCPAY_WEBHOOK_SECRET` before fulfillment. For programmatic access prefer `btcpay-greenfield-node-client`.
- ⚑Self-hosting means you are responsible for node uptime, backups, and Lightning channel liquidity — outages = lost sales.
- ⚑Lightning channels need active management: inbound liquidity for receiving, outbound for payouts; closing/reopening costs on-chain fees.
- ⚑On-chain BTC payments have probabilistic finality; pick a confirmation policy (typically 1-2) and disclose it to merchants and customers.
- ⚑Greenfield API is the modern path; the legacy BitPay-compatible API is feature-limited and slated for deprecation — don't build new integrations against it.
- ⚑Webhook delivery is at-least-once: implement idempotency on `invoiceId` to avoid double-fulfilling orders.
- ⚑Time-locked invoices expire fast (default 15 minutes) — exchange-rate volatility can cause underpayment if the customer waits.