Creating Invoices

Invoices are one-time, addressable payment requests. Use them when you want a specific amount paid for a specific thing.

Unlike direct payments (which accept any amount), an invoice has a fixed amount, an expiry, and optional rules for partial or overpayment. Each invoice is a record on-chain — you, your customer, and anyone else can verify its state with a block explorer.

Creating an invoice

From the dashboard:

  1. Go to Invoices
  2. Click New Invoice
  3. Fill in the form and confirm the transaction in your wallet

Fields you'll fill in:

ParameterTypeDescription
Amountrequiredsats / micro-STXThe exact amount due. For sBTC, 100,000,000 sats = 1 BTC. For STX, 1,000,000 micro-STX = 1 STX.
TokenrequiredsBTC | STXWhich token the customer pays in.
Memostring (max 280)Short description customers see on the payment page.
Reference IDstring (max 64)Your internal order/reference ID. Useful for reconciliation.
Expires inburn blocks
default: 4320 (≈30 days)
How long the invoice accepts payment before expiring. Counted in Bitcoin blocks.
Allow partialboolean
default: false
If true, customer can pay less than the full amount. Status becomes 'Partial' until total = amount.
Allow overpayboolean
default: false
If true, customer can pay more than the amount. Extra is treated as a tip.

Picking an expiry

The default is 30 days. For digital goods, 24 hours is usually enough. For invoices sent by email with a longer decision cycle, 7–30 days is typical. Shorter expiries reduce risk of price drift if Bitcoin moves significantly.

Invoice lifecycle

Every invoice moves through a defined set of states:

StatusTypeDescription
Pending0Created, no payment yet.
Partial1Received some payment, but less than the full amount. Only reachable if allowPartial = true.
Paid2Received full amount (or more, if allowOverpay = true). Terminal state for successful invoices.
Expired3Past the expiry block without being fully paid.
Cancelled4Merchant cancelled before any payment was made.
Refunded5After being paid, full amount was refunded to the customer.

Sharing an invoice with your customer

Every invoice has two shareable surfaces:

1. Public payment page

Send your customer this URL — they open it, connect their wallet, and pay:

https://sbtc-pay.com/pay/{invoiceId}

No code or embedding required. Works great in an email, Telegram message, or chat.

2. Embeddable invoice widget

For a checkout page where the invoice lives on your site, drop the SDK in and reference the invoice ID. See Widget Overview for full details.

html
<script src="https://sbtc-pay.com/sbtcpay.js" async></script>

<div data-sbtcpay="invoice" data-sbtcpay-invoice="{invoiceId}"></div>

Partial payments

If allowPartial is enabled, the invoice can accept multiple smaller payments until the total is reached. Each partial payment is its own on-chain transaction, and shows up as a separate row in the invoice's payment history.

Use partial payments for:

  • High-value invoices where the customer prefers to pay in tranches
  • Milestone-based work (e.g., 30% deposit, 70% on delivery)
  • Any case where exact-amount enforcement would be a bad UX

Overpayments

If allowOverpay is enabled, the customer can pay more than the invoice amount. The excess goes to the recipient along with the base amount. This is common for content creators, fundraisers, and any "pay what you want" flow.

One or the other — usually

Partial and overpay are independent flags. It's valid to enable both, but this can produce confusing UX ("did I pay enough?"). Enabling just one is the usual pattern.

Cancelling and updating

Before any payment is made, you can cancel the invoice or update its amount, memo, or expiry. Once any payment arrives, the invoice is locked and can only be refunded.

Refunding

After an invoice is paid, you can refund it fully or partially. See Processing Refunds for the full flow.

Fees

sBTC Pay takes a small protocol fee on every payment. The fee is deducted automatically — the merchant sees the net amount as merchant-received in the dashboard. Current fee schedule is on the landing page's pricing section.