Processing Refunds

Issue full or partial refunds for any completed payment. All refunds are on-chain and auditable.

A refund moves funds from your wallet back to the payer's wallet. You can refund partially (useful for price adjustments) or fully. There's a bounded refund window, so refunds can't be issued indefinitely after payment.

Issuing a refund

  1. Go to Invoices in the dashboard
  2. Find the paid invoice and click it
  3. Click Refund
  4. Enter the refund amount (can be less than the invoice amount for a partial refund)
  5. Optionally include a reason that gets recorded on-chain
  6. Confirm the transaction in your wallet

When the transaction confirms, the funds move from your wallet back to the customer's wallet, and the invoice's amount_refunded increases.

Refund states on the invoice

  • Partial refund — if amount_refunded < amount_paid, the invoice stays in its current status but records the partial refund.
  • Full refund — when amount_refunded ≥ amount_paid, the invoice status changes to Refunded (status 5). This is terminal for the invoice.

Multiple partial refunds are supported

You can issue several partial refunds against the same invoice. The contract keeps a running total and only moves the invoice to "Refunded" when the full amount has been returned.

The refund window

Refunds can only be issued within a bounded window after the invoice's first payment. This prevents indefinite clawback and gives customers certainty that after enough time, funds are final.

The window is measured in burn blocks from the first-payment-at block. Check the contract source for the exact constant — it's currently set to a value that gives merchants a comfortable window for dispute handling but not indefinite.

Subscription payment refunds

You can refund individual subscription payments the same way you refund invoice payments. Each subscription payment is an independent on-chain event — refunding one payment doesn't affect the rest of the subscription, and doesn't automatically cancel it.

What's recorded on-chain

Every refund emits a refund-processed event with:

  • The refund ID (unique per refund)
  • The invoice ID being refunded
  • The amount refunded
  • The reason (optional string you provide)
  • The burn block at which the refund was processed

This means anyone can audit the full refund history of a merchant with a block explorer — useful for transparency and dispute resolution.

Common scenarios

Customer requested a return

Issue a full refund. Customer receives the full amount back, invoice marks as Refunded.

Customer wants a price adjustment

Issue a partial refund for the difference. Invoice remains Paid, but amount_refunded reflects the partial return.

Chargeback equivalent

In crypto there's no "chargeback" — you control the refund. If a payer disputes a charge, you have full discretion to refund or not. This means you take on the dispute burden that card networks normally handle — factor that into your fraud policy.

Errors you might hit

  • Refund window expired — the invoice is too old. See the Error Codes page for the exact constant.
  • Insufficient balance — your wallet doesn't have enough sBTC/STX to cover the refund. Top it up before retrying.
  • Already fully refunded — someone (you, or an automated process) already refunded the full amount.