🎉 Celebrate with 10% OFF on All Products! Use Code: GFEX10 Or Buy Any 2+ Items for 30% OFF with Code: GFEX30!
Guides & Tutorials November 9, 2026

How to Accept Bitcoin with Gravity Forms and Your Own BTCPay Server

GravityExtra
How to Accept Bitcoin with Gravity Forms and Your Own BTCPay Server

More and more small businesses want to accept Bitcoin without handing their payments to a middleman. BTCPay Server makes that possible: it is free, open-source software that you run yourself, and payments go straight to the wallet of your store. What it does not do on its own is talk to your WordPress forms. In this tutorial you will connect Gravity Forms to your own BTCPay Server, so a booking, order or donation form creates an invoice for the exact total and the customer pays it on your BTCPay Server checkout page.

We use the Gravity Forms BTCPay Server Premium Add-on throughout. It creates the invoice on your server, checks every webhook signature, reads every invoice back before an entry is marked paid, and lets you create refund links from the entry screen.

What you need before you start

  • A running BTCPay Server on a public https address, with a store that has a wallet (on-chain) and, if you like, a Lightning node connected.
  • A rate source in the store settings that covers the currency of your forms, for example US dollars or euros.
  • A WordPress site on https with Gravity Forms 2.9 or newer.
  • About twenty minutes and a test store (a testnet or regtest server is ideal for practice).

Self-hosted means you are in charge

Your BTCPay Server is the system of record for every payment. The plugin never holds funds and never sees wallet keys: it creates invoices and reads them back with an API key limited to one store.

How the pieces fit together

It helps to picture the flow once before clicking through settings. Gravity Forms works out the total on your WordPress server. The plugin sends that total, in your form currency, to the Greenfield API of your BTCPay Server and gets back an invoice with a checkout link. The customer is sent to that link, picks on-chain or Lightning, and pays. BTCPay Server converts the amount with the rate source of your store, watches the network, and moves the invoice through its statuses: New, Processing (paid, waiting for confirmations) and finally Settled. On every change it can send a signed webhook to your site.

The important design choice is that the webhook is treated as a doorbell, not as proof. When it rings, the plugin asks your BTCPay Server directly for the invoice and only marks the entry Paid when the invoice is Settled for the right amount, currency, store and order ID. The same check runs when the customer comes back to your site and every five minutes, so a missed webhook never leaves an entry stuck.

Step 1: Prepare the store in BTCPay Server

  1. Open your store in BTCPay Server and copy the Store ID from Store Settings → General.
  2. Check Store Settings → Rates: pick a rate source that has a rate for your form currency. Without it, BTCPay Server cannot create invoices in that currency.
  3. Decide how many confirmations you want before an order counts as paid. You can set this in the store, or later in the plugin per site.

Step 2: Create a limited API key

Open Account → Manage Account → API Keys and generate a new key. Limit it to the store you just prepared and tick only what the plugin needs: View invoices, Create an invoice, and Create non-approved pull payments if you want refund links. A narrow key is good practice: if it ever leaked, it could not move funds or change your store.

Step 3: Connect Gravity Forms

BTCPay Server settings: Test or Live mode, the server address, store ID and masked API key and webhook secret of each mode, confirmations before Paid, invoice expiry, the currency line, the connection line and the webhook address
Settings: the address of your own BTCPay Server, the store ID, an API key and the webhook secret for each mode.

Install the plugin, activate your licence in Forms → Settings → BTCPay Server, and keep the mode on Test. Enter the https address of your test server, the store ID and the API key, then save. The plugin checks the key by listing one invoice of the store, so nothing is created during the check. You should see “Connected to BTCPay Server” with your server name and a masked key, for example the first and last four characters only.

Two extra settings are worth a look. Confirmations before Paid lets you choose between the store setting and high, medium, low-medium or low speed (0, 1, 2 or 6 on-chain confirmations). Lightning payments settle at once either way. Invoice expiry sets how long the customer has to pay; leave it empty for the store setting, which is 15 minutes by default.

A note on server addresses

Because the server address is typed in by you, the plugin treats it carefully: https only, no user names or query strings, no redirects, and the host must not point to a private or local network address. If your site and server share a private network, a developer filter can allow it.

Step 4: Add the webhook

Copy the webhook address from the plugin settings. In BTCPay Server, open Store Settings → Webhooks → Create Webhook, paste the address, keep automatic redelivery on, and choose the invoice events or simply send everything. BTCPay Server shows a secret for the webhook: copy it into the webhook secret field of the plugin and save. From now on every delivery carries a BTCPay-Sig header, a keyed hash of the message, and the plugin refuses anything whose signature does not match.

Step 5: Build the form and the feed

A bike service booking form with quantities, the customer name and email, and the total of $285.50, with the Continue to payment button
The form: Gravity Forms works out the total in your currency; BTCPay Server converts it on the checkout page.

Any Gravity Forms form with product fields or a total works. Our example is a bike workshop that sells a full service for $120.00 and a new chain and cassette for $45.50. Two services and one chain make $285.50. In the form settings, open BTCPay Server and add a feed: choose Products and Services, the form total as the amount, map the name and email fields, and write a description such as “Bike service #{entry_id}”. That description appears on the invoice in BTCPay Server, which makes it easy for your team to find a payment.

The BTCPay Server feed: products and services with the form total, the customer name and email mapping, the invoice description with merge tags and notifications after payment
The feed: map the customer name and email, and write the description shown on the invoice in BTCPay Server.

Tick “Send form notifications only after the customer has paid” if your booking email should wait for the payment. The plugin holds the notifications and sends them once, as soon as the invoice is Settled.

Step 6: Make a test payment

Open the form, fill it in and submit. You land on the checkout page of your test server with the amount in your currency and the equivalent to pay. Pay it with a test wallet. Depending on your confirmation setting, the page sends you back at once or after the first confirmation. Back on your site, the customer sees either the thank-you message or a clear “payment received, waiting for network confirmation” note, and the page checks again by itself.

An entry paid through BTCPay Server: the box with the status, amount, invoice, order ID, BTCPay Server status, payment method and payment ID, the refund link for the customer, the Refresh status button and the refund form
The entry: status, invoice and payment details read back from your server, and a refund link for the customer.

In Forms → Entries the entry shows Paid, the invoice ID as the transaction ID, and a note with the payment method (for example on-chain) and the payment ID. The BTCPay Server box on the right shows the same details and the current invoice status.

What each invoice status means for your entries

BTCPay Server invoice Entry
New (not paid yet) Processing. After three days without a payment the entry is set to Cancelled (a later settlement is still recorded).
Processing (paid in full, waiting for confirmations) Processing, with a note. The return page tells the customer the payment was received and is waiting for network confirmation.
Settled Paid, after the amount, currency, store and order ID match the entry. Notes mention a hand-marked or overpaid invoice.
Expired, nothing paid Cancelled
Expired after a partial or late payment Pending, with a note asking you to review the invoice. Never marked Paid automatically.
Invalid Failed

Two cases deserve a closer look. When an invoice is paid in full but still waiting for confirmations, the entry stays Processing and gets a note; nothing is fulfilled early. When an invoice expires after the customer paid only part of the amount, or paid after it expired, the entry becomes Pending with a note. The plugin never marks these Paid on its own, because only you can decide whether to accept the payment, ask for the rest, or refund it. If you mark the invoice as settled in BTCPay Server, the next read-back marks the entry Paid with a note that it was marked by hand.

Refunds with refund links

Refunds in BTCPay Server work differently from card refunds: you do not know the customer’s address, so you create a refund link and the customer enters their own address there. On a paid entry, type the amount in the BTCPay Server box and click Create refund link. The plugin reads the invoice back first, then asks your server for a refund in the invoice currency. Copy the link from the entry box and send it to the customer. When they claim it, approve and send the payout in BTCPay Server.

The entry does not pretend a refund happened before it did. It records the refund only when BTCPay Server shows the payout as Completed, once per payout, and the entry becomes Refunded when the whole amount has been paid out. Partial refunds are fine: create a link for part of the amount, and later another one for the rest.

A worked example

Northfield Bike Workshop prices services in US dollars. On a Saturday morning a customer books two full services and a new chain: $285.50. The plugin creates an invoice for “285.50” USD with a unique order ID and sends the customer to the shop’s BTCPay Server. The customer pays over Lightning; the invoice settles within seconds and BTCPay Server sends the InvoiceSettled webhook. The signature is valid, so the plugin reads the invoice back: Settled, 285.50 USD, the right store and order ID. The entry becomes Paid, the held booking email goes out, and the workshop sees the payment in both Gravity Forms and BTCPay Server. A week later one service is cancelled; the workshop creates a refund link for $120.00, the customer claims it, the payout is sent, and the entry records the refund with $165.50 left.

Why this setup is safe by design

  • Your server, your keys. The add-on talks only to the BTCPay Server you run, with an API key limited to one store and three permissions.
  • Settled means Paid, nothing less. A webhook only tells the add-on to look; the invoice is read back from your server, and only a Settled invoice with the right amount, currency, store and order ID counts.
  • Confirmations are respected. Payments waiting for the network keep the entry waiting with a clear message to the customer.
  • Partial and late payments go to you. They become Pending with a note so a person decides, instead of being marked Paid.
  • Refunds without asking for addresses by email. A refund link lets the customer enter their own address on your BTCPay Server, and the entry records the refund only when the payout is completed.

Tips for smooth payments

  • Choose the confirmation speed that fits your goods: instant downloads can use high speed, expensive orders may wait for more confirmations.
  • Keep the invoice expiry long enough for on-chain payments; 15 to 30 minutes works for most forms.
  • Write descriptions with the entry number so you can match payments quickly in BTCPay Server.
  • Check the Webhook line in the plugin settings after your first payment: it shows when the last valid webhook arrived.
  • If your BTCPay Server is behind a reverse proxy, make sure it forwards the original host and https scheme, so checkout links point to your public address.

Going live

When your tests look right, fill in the Live fields with your production server, store ID, API key and webhook secret, create the webhook in the production store, switch the mode to Live and save. Make one small real payment and one small refund link. Every entry remembers the mode, server and store it was created with, so your test entries keep reading from the test server.

Questions

Does the plugin hold or move funds?

No. Payments go to the wallet of your BTCPay Server store. The plugin only creates invoices and refund links and reads invoices back.

Which currencies can my forms use?

The currencies Gravity Forms ships, such as USD, EUR, GBP, CAD, AUD, CHF and JPY, as long as the rate source of your store covers them.

What if a webhook is missed?

The plugin also reads the invoice when the customer returns and every five minutes, and you can click Refresh status on any entry.

Are recurring payments supported?

Not in this version. The plugin handles one-off payments for products, services and donations.

Get started

Get the Gravity Forms BTCPay Server Premium Add-on and follow the setup guide. Plans: one site $49 a year, five sites $69 a year, unlimited sites $199 a year.

0
0
Your Cart
Your cart is emptyReturn to Shop
🔥 FREQUENTLY BOUGHT TOGETHER
Complete Combo & Save 40%!
ITEM IN YOUR CART
Gravity Forms Klaviyo Add-on
$39.00/yr
+
🎁 RECOMMENDED ADD-ON SAVE 40% OFF
Original Price: $39.00/yr
Bundle Special Price: $23.40/yr