Displaying Invoices

Because Bitcoin works as a push transaction, rather than using the traditional authorize and capture process (pull) as does a credit card, you must accomodate this in your checkout flow.

While a traditional checkout flow would collect credit card info and then present a “finalize order” page and subsequently charge the card, with Bitcoin, no details need to be collected prior to confirmation. A click on “confirm order” should present a modal or blocking payment screen which will provide a bitcoin invoice for payment, then proceed to confirmation once the payment is received.

Redirect to BitPay

The simplest integration is to simply redirect your customer to the BitPay site to complete payment, then return them to your site for order confirmation. In this case, you need only redirect your customer to the url returned in the JSON response from the /invoices endpoint.

You can do this most easily by using one of our supported integrations or directly with one of our supported libraries.

The BitPay invoice uses responsive design to ensure that the user gets optimal presentation regardless of device form factor.

Be sure that you have also set the redirectURL when generating the invoice, which will ensure that the user gets redirected to the appropriate confirmation page following payment.

You should always validate that the invoice was paid by re-querying the BitPay API, or by manually validating that it appears in your account ledger, before completing the transaction.

Modal Invoice (iFrame)

BitPay allows you display the invoice within a modal on your web page, so the shopper never has to leave your site during the checkout process.

Modal invoice demo:

  1. To use the modal invoice, add bitpay.js to your web page:
  2. <script src="https://bitpay.com/bitpay.js"></script>
  3. When you create an invoice with a POST request to BitPay, BitPay returns the id of the invoice as part of the request response.
  4. To display the newly created invoice within a modal, pass the invoice id into the showInvoice method provided by bitpay.js:
  5. bitpay.showInvoice(id);
  6. The modal invoice will automatically update when payments have been received. In addition to the server IPN sent to your notificationURL, the modal iframe will send a message to the parent window that the status has changed.

Additional methods provided by bitpay.js include:

  • onModalWillEnter: Allows you to specify a function to be called right before the modal opens.
  • onModalWillLeave: Allows you to specify a function to be called when the user closes the modal.
  • enableTestMode: Allows you to display invoices created via https://test.bitpay.com.
bitpay.onModalWillEnter(function() {
  console.log('modal is opening');

bitpay.onModalWillLeave(function() {
  console.log('modal is closing');


It is highly recommended that you include the email of the buyer as part of the buyerFields.buyerEmail field when creating the invoice via the BitPay API. The buyerEmail field will be used by BitPay to contact the buyer in the case of an underpayment or overpayment in order to administer a refund. If you do not provide the buyerEmail field, BitPay will prompt the user for an email address when the modal opens.

Embedded Invoice (iFrame)

BitPay also allows you to embed the invoice directly into a 500 x 150px block on your web page.

  1. When you create an invoice with a POST request to BitPay, BitPay returns the url field, which is the URL at which this invoice can be viewed.
  2. To display the embedded invoice on your page, append the code &view=iframe to the invoice URL and specify this value as the src in an iframe.
  3. The embedded invoice will automatically update when payments have been received. In addition to the server IPN sent to your notificationURL, the iframe will send a message to the parent window that the status has changed.

If your website has a dark background theme, append the code &theme=dark to the invoice URL. Note that the iframe background color is transparent.

<iframe id="bitpay_invoice_iframe"
  frameborder="0"  src='https://test.bitpay.com/invoice?id=LxuN1nQwB3UKTVuamJeLSi&view=iframe'
  style='width:500px; overflow: hidden; padding:20px; max-width:100%'>

Post to Parent Window

When an invoice is presented in an iframe you have an option to receive invoice status updates in the parent window. This option is useful for updating the parent window presentation or redirecting the parent window to another URL after the invoice has been paid.

When the invoice iframe receives a status update from the BitPay server the new status is posted from the invoice iframe to the parent window via the Window.postMessage method and passing {status: string} where status can be any of the Invoice States according to the descriptions provided.

Your implementation should take into consideration the browser support for this method. See CanIUse for a list of browsers supporting Window.postMessage.

Following is an HTML code example illustrating a simple interaction between an invoice iframe and its parent document.

    <p>Invoice status: <span id="s1"></span>
    <iframe src="https://bitpay.com/invoice?id=UbAd3j1E7ivCe5i9t88obd" style="width: 800px; height: 800px;"></iframe>
    <script language="javascript">
  window.addEventListener("message", function(event) {
  }, false);

Custom Invoices

There are instances when it is not possible to directly display the presentation of a BitPay server generated HTML invoice (either the full page or the iframe). This occurs when the system requesting an invoice is interacting with the customer via a device that does not directly present or render HTML content. Example use cases include:

  • Proprietary gaming platforms
  • Custom embedded display devices (gas pump, kiosk device)

Constructing an invoice typically requires that the implementation generate it’s own QR (Quick Response) code, enabling custom interaction with a Bitcoin wallet, and/or making the bitcoin address visible to receive payment. Additional considerations include:

  • Time limit - the client must ensure that presentation of the invoice does not exceed the maximum time allowed by BitPay to present payment. Currently the time limit is 15 minutes.
  • Prices - the invoice should display both the bitcoin price as well as the local currency price. It is not recommended to display the bitcoin/local currency exchange rate as this could be confusing to the buyer.
  • Bitcoin address - in some settings it may be convenient to display (or otherwise present) the bitcoin address for copy and paste. This is useful if the buyer must transfer the bitcoin address to their bitcoin wallet manually.
  • Other information - details about the product or service being purchased, an order identifier, the merchant name, address, etc.

Invoice Status Updates

Use of the BitPay server provided invoice URL for presentation of the invoice includes the benefit of the client presented invoice receiving socket messages from the BitPay server when invoice status changes. For example, subsequent to paying an invoice the BitPay server will update the status of the invoice and send that status via a direct socket connection between the BitPay server and the invoice presenting web browser client. When presenting a custom invoice this socket connection is not possible. The only means for updating the presentation of the invoice (e.g., to show ‘paid’ status) is to receive the invoice IPN at your server and then to update your invoice presentation (e.g., using AJAX) at the client.

Generating a Custom QR Code Image

The QR code is a digitally encoded image that contains the Bitcoin payment URI. The BitPay server supports both the old style (BIP 72) Bitcoin protocol (for backwards compatibility) as well as the new style (BIP 73) Bitcoin Payment Protocol.

When choosing to generate your own QR code image you must make a choice between the two style of URI you wish to encode in the image. For maximum compatibility with wallets you should choose to encode the BIP 72 compatible URI. This URI scheme can be scanned successfully by all existing Bitcoin wallets. As more wallets provide support for the Bitcoin Payment Protocol you may choose to switch from using the BIP 72 compatible URI to the BIP 73 compatible URI. The density of a BIP 72 QR code is higher than that of a BIP 73 QR code and may result in increased scanning errors.

Attached in the invoice payload are different paymentUrls which can be encoded according to your implementation preferences:

"paymentUrls": {
  "BIP21": "bitcoin:mvYRECDxKPaPHnjNz9ZxiTpbx29xYNoRy4?amount=0.3745",
  "BIP72": "bitcoin:mvYRECDxKPaPHnjNz9ZxiTpbx29xYNoRy4?amount=0.3745&r=https://bitpay.com/i/NKaqMuZWy3BAcP77RdkEEv",
  "BIP72b": "bitcoin:?r=https://bitpay.com/i/NKaqMuZWy3BAcP77RdkEEv",
  "BIP73": "https://bitpay.com/i/NKaqMuZWy3BAcP77RdkEEv"
Instant Payment Notifications (IPNs)