Sandbox invoice remains PAID after the full payment refund is COMPLETED

We reproduced an invoice/refund status disagreement in the Square Sandbox with two entirely synthetic test invoices.

  1. Create an order and invoice, then publish with SHARE_MANUALLY.
  2. Pay the invoice on Square’s hosted sandbox payment page using the official test card.
  3. Retrieve the payment ID from the order and call RefundPayment once for the full amount.
  4. Independently retrieve the invoice, payment and refund after processing.

Both PaymentRefund objects are COMPLETED, and each Payment.refunded_money equals the full original payment. However, both Invoice objects remain PAID at version 2, with unchanged updated_at. All readbacks return HTTP 200. The same result occurs with API versions 2026-08-19 and 2026-09-16, including repeat reads at 15:49, 16:09 and 19:56 UTC on September 16.

The Pay or Refund Invoices guide says a full refund changes the invoice to REFUNDED and updates its version/timestamp. Is there a known sandbox propagation limitation? What supported readback should establish invoice closure before a corrected replacement is created?

We have held replacements and have not attempted another refund or an invoice-status override. No production transaction or customer data is involved. We can provide the exact sandbox resource IDs through a supported private channel if needed.

Reference: Pay or Refund Invoices

@MBSM - This is a known sandbox parity gap. The Pay or Refund Invoices docs are correct that a full refund should transition the invoice to REFUNDED with an updated version and updated_at for production-level invoices. The PaymentRefund objects completing correctly while the invoice stays PAID is consistent with the sandbox’s known divergence from production behavior.

Square’s standing guidance is to use a separate free production account for end-to-end testing of flows like invoice lifecycle transitions. To simulate payment activity without moving real money, use CASH or EXTERNAL tender types.