Partial Refunds
Issuing a refund for less than the full payment amount, typically for individual line items, prorated usage, or goodwill credits, while tracking the remaining refundable balance.
Description
Partial refunds allow you to return a portion of a payment to the customer while retaining the rest. This is common in scenarios like refunding a single item from a multi-item order, providing a prorated refund for unused subscription time, or offering a goodwill discount after a service issue. Stripe supports partial refunds natively: pass an amount parameter (in cents) to stripe.refunds.create() that is less than the original charge amount. Multiple partial refunds can be issued against the same charge as long as the cumulative refund total doesn't exceed the original payment.
The engineering complexity of partial refunds lies in tracking the refundable balance and mapping refunds back to specific line items or business reasons. Your system should maintain a running total of refunded amounts per payment and calculate the remaining refundable balance on demand. For multi-item orders, each refund should reference the specific order line item(s) being refunded, which feeds into inventory management (restocking), revenue recognition, and tax adjustment calculations. A refund line items table (refund_id, order_line_item_id, quantity, amount) provides this granularity.
Tax implications of partial refunds add additional complexity. If you collected tax on the original payment, the refund should proportionally reduce the tax amount. Stripe Tax handles this automatically when you use credit notes on invoices, but for PaymentIntent-based refunds, you may need to calculate the tax adjustment yourself. Some jurisdictions require that refunds reduce the taxable amount, which must be reflected in your accounting records and tax filings.
Prompt Snippet
Issue partial refunds with stripe.refunds.create({ payment_intent: pi_id, amount: lineItemAmount }) and track the refundable balance by querying SELECT original_amount - COALESCE(SUM(refund_amount), 0) as refundable FROM payments LEFT JOIN refunds ON payments.id = refunds.payment_id WHERE payments.id = ?. Model refund line items in a refund_items table (refund_id, order_item_id, quantity, unit_amount, tax_amount) to maintain auditability of what was refunded and why. When refunding taxed payments, calculate the proportional tax refund as (refund_amount / subtotal) * tax_amount and include it in the total refund amount. Validate that the requested partial refund amount does not exceed the remaining refundable balance before calling the Stripe API.Tags
Related Terms
Refund Flow Design
Designing the end-to-end process for returning funds to customers, including full and partial refunds, internal state management, and integration with Stripe's Refund API.
Tax Calculation Integration
Automatically calculating and collecting the correct sales tax, VAT, or GST amount based on the customer's location, product type, and applicable tax rules using services like Stripe Tax.
Ledger / Transaction Log Design
Designing an append-only transaction log that records every financial event with double-entry bookkeeping principles, providing a complete audit trail and enabling balance reconciliation.
Invoice Generation
Creating and managing invoices for one-time charges and subscription billing cycles, including line item customization, tax itemization, and PDF generation through Stripe's Invoice API.