Refund Handling
Issue a refund from your store admin and Split Pay PRO automatically reverses the associated Stripe transfers — proportionally for partial refunds, fully for complete refunds. Works on both WooCommerce orders and FluentCart orders. Manual reversal options are also available via the Stripe Dashboard or API.
Automatic Refund Handling PRO#
Transfers are reversed automatically. When you issue a refund from your store admin (WooCommerce or FluentCart), Split Pay PRO calculates the refund ratio and reverses each transfer proportionally. No manual Stripe Dashboard interaction is needed.
Split Pay listens for refund events on whichever platform is processing the order:
- WooCommerce orders — Split Pay hooks into the
woocommerce_order_refundedaction. - FluentCart orders — Split Pay hooks into FluentCart’s refund event (see the FluentCart integration page for the exact hook). The reversal logic is identical.
You issue a refund — Navigate to the order in your store admin (WooCommerce → Orders or the FluentCart → Orders screen), open the order, click Refund, enter the amount, and confirm.
Split Pay calculates the refund ratio — The plugin compares the refund amount to the original order total. A $50 refund on a $200 order produces a ratio of 25%.
Each transfer is reversed proportionally — The plugin retrieves every transfer recorded for that order and creates a Stripe transfer reversal for the proportional amount.
Order notes are added — Each reversal (success or failure) is documented as an order note on the originating store order, plus a summary at the end.
Full refund example#
A $150 order with two transfers:
| Transfer | Original Amount | Reversal Amount |
|---|---|---|
| Vendor A (acct_xxx) | $45.00 | $45.00 (100%) |
| Vendor B (acct_yyy) | $30.00 | $30.00 (100%) |
Order notes created:
- "Split Pay: Reversed transfer tr_xxx to acct_xxx — $45.00 (full reversal)"
- "Split Pay: Reversed transfer tr_yyy to acct_yyy — $30.00 (full reversal)"
- "Split Pay Refund Summary: 2 transfer(s) reversed, 0 failed. Refund ratio: 100%"
Partial refund example#
Same $150 order, but only a $37.50 refund (25%):
| Transfer | Original Amount | Reversal Amount |
|---|---|---|
| Vendor A (acct_xxx) | $45.00 | $11.25 (25%) |
| Vendor B (acct_yyy) | $30.00 | $7.50 (25%) |
Handling failed reversals#
A transfer reversal can fail if the connected account doesn't have sufficient balance (e.g., the vendor already paid out their funds). When this happens:
- The failure is logged as an order note with the Stripe error message.
- Other transfers in the same refund continue processing — one failure doesn't block the others.
- The summary note reports the count of successful and failed reversals.
If a vendor's Stripe balance is insufficient, you'll need to wait for new payments to build up their balance, or handle the reversal manually once funds are available. Check the order notes for the specific error.
Requirements for automatic reversals#
- Split Pay PRO — Automatic refund handling requires the PRO version.
- Transfer log entries — The plugin reverses transfers recorded in its transfer log. Orders placed before the plugin was installed won't have log entries and must be reversed manually.
- Same currency — Reversals must be in the same currency as the original transfer (this is a Stripe requirement).
- Connected account balance — Vendors must have sufficient Stripe balance to cover the reversal amount.
- Refund issued through your store admin, not directly in Stripe — This applies to both WooCommerce and FluentCart. A refund initiated directly in the Stripe Dashboard bypasses the platform refund event Split Pay listens for. See the FluentCart-specific refund-handling note for details on Stack B’s refund event.
Manual reversals via Stripe Dashboard#
You can reverse transfers manually through the Stripe Dashboard. This is useful for free version users, orders placed before the plugin was installed, or edge cases not covered by the automatic process.
Log in to the Stripe Dashboard.
Navigate to Connect → Transfers (or find the transfer via the original payment).
Click on the transfer, then click Reverse transfer.
Enter the full or partial amount to reverse, then confirm.
Reversals via the Stripe API#
You can also reverse transfers programmatically using the Stripe Transfer Reversals API. Don’t hard-code your secret key — load it from an environment variable, a secret manager, or your hosting platform’s config so it never lands in version control:
// Load your platform secret key from the environment, NOT a literal.
// It will start with sk_test_ in test mode or sk_live_ in live mode,
// or rk_test_ / rk_live_ if you are using a restricted key with
// "Connect → Transfers: Write".
$stripe = new \Stripe\StripeClient(getenv('STRIPE_SECRET_KEY'));
// Reverse the full transfer
$reversal = $stripe->transfers->createReversal(
'tr_TRANSFER_ID',
[]
);
// Partial reversal
$reversal = $stripe->transfers->createReversal(
'tr_TRANSFER_ID',
['amount' => 1000] // $10.00 in cents
);
Never commit a literal sk_live_… key. Stripe automatically scans public GitHub for live secret keys and will revoke any it finds, but a leaked key can still be abused before that happens. Use environment variables, your hosting platform’s secret store (e.g. Cloudflare Workers Secrets Store, Vercel env vars, WP-CLI wp config set STRIPE_SECRET_KEY), or a dedicated secret manager.
It's a good practice to communicate with your vendors before reversing a transfer so they understand why funds are being pulled back from their account.
Retrying failed transfers#
If transfers fail during initial processing (e.g., due to network issues or temporary Stripe errors), you can retry them directly from the order page. See Retry Failed Transfers for details.
Technical implementation#
For developers and store owners who want to understand the internals:
- WordPress hook:
woocommerce_order_refunded(priority 10, receives$order_idand$refund_id) - Refund ratio calculation:
refund_amount / order_total - Stripe API: Uses
$stripe->transfers->createReversal()— full amount when ratio is 100%, calculated amount for partial refunds - Transfer lookup: Queries the
bsd_scsp_transfer_logdatabase table for all successful transfers matching the order ID - Error isolation: Each reversal is wrapped in its own try/catch block so individual failures don't prevent other reversals