Fixed upstream
Bugs in open-source payment code where a payment ends in the wrong state: the customer is charged and gets no order, or the webhook is acknowledged and the provider stops retrying. Each was reproduced against the project's own code before it was reported, with a test in the project's suite or a harness in callback-audit.
Status as of 11 November 2026.
Fixed (33)
- Blnk · bulk transactions: an atomic bulk request in the default queued mode is not rolled back when one item is rejected, so the other items stay applied, contrary to the documented all-or-nothing behaviour. Fixed by my PR, merged 10 Nov, not yet released. #413 · PR #414
- Open SaaS · Lemon Squeezy: with the webhook events the setup guide lists, a subscription that ends arrives as an update the handler ignores, so the user keeps paid access after it has expired. Fixed by the Wasp team on 6 Nov in the template’s main branch: subscription statuses now map the way the Stripe ones do, and an expired subscription loses access. #765 · fix #767
- Open SaaS · Lemon Squeezy: a credits purchase by a customer without a subscription is answered 400 on every delivery, so the credits are never added. Fixed by the Wasp team on 6 Nov in the template’s main branch: the webhook no longer calls the Lemon Squeezy API before it adds the credits. #755 · fix #767
- Payment Plugins for Stripe WooCommerce: when one read of the PaymentIntent fails while a succeeded event is handled, the plugin puts a new PaymentIntent on the order in place of the paid one and still answers 200, so a paid SEPA order stays on-hold and a manual resend from Stripe finds no order. Fixed by Payment Plugins, released in 4.0.20 on 6 Nov: a failed read no longer replaces the paid PaymentIntent, and resending the event from Stripe now completes the order. forum topic
- Flexprice · Stripe: amounts in currencies without minor units, such as JPY and KRW, are multiplied by 100 when a saved card is charged or an invoice is synced to Stripe, so a ¥12,000 invoice is charged as ¥1,200,000 while Flexprice still shows ¥12,000. Fixed by the Flexprice team in their 5 Nov release: Stripe amounts are now converted using each currency’s precision, both when a saved card is charged and when invoices and payments are synced. #3222
- Cargo · Mollie: when the cart changes after a Mollie payment was created, the old payment stays open, and if the customer still pays it the webhook finds neither the order nor the cart and answers 200, so the customer is charged, there is no order and nothing is refunded. Fixed by my PR, merged 6 Nov, released in 1.17.1 on 9 Nov. #355 · PR #356
- Spree · payment webhooks (Stripe): the webhook job catches every error while it settles the payment and finishes as if it succeeded, so its retries never run; a buyer who paid and didn't come back from the payment page is charged, Stripe already got 200, and there is no order. Fixed by Spree on 6 Nov in the main branch, not yet released: the job now fails when settlement fails and is retried with backoff. #15132 · fix #15133
- Simple Commerce · Mollie and PayPal: a Mollie payment made before the checkout page was shown again is never matched to its order, so the paid order stays unpaid, and a PayPal order is marked paid while its capture is still pending or was declined. Fixed by my PR, merged 5 Nov, released in 8.1.2 and 7.8.12. #1312 · PR #1313
- Adyen for Shopware 6: a successful authorisation for a transaction that Shopware has already marked failed is processed without paying it, so the captured order stays failed. Fixed by Adyen, released in 5.4.3 on 5 Nov (and in 4.7.3 and 3.22.3 for older Shopware versions): a transaction that failed on the payment details call is now settled when the successful authorisation arrives. #895
- WooCommerce Stripe Gateway · cancelled orders: a payment that succeeds for an order already cancelled when Stripe reports it is dropped before the deferred job that should refund it, so the shopper stays charged for a cancelled order. Fixed by WooCommerce on 5 Nov in the development branch, not yet released (planned for 11.2.0): the event for a cancelled order is now deferred before the status check, so the payment is refunded or the authorisation voided. #6130 · PR #6131 · fix #6147
- Simple Membership · Stripe: reported privately to the developers. Fixed by the maintainers in 4.8.7. Checked against the released code.
- Paid Member Subscriptions · Stripe: reported privately to the developers. Fixed by the maintainers in 3.1.4. Checked against the released code.
- LNbits · PayPal: capture events carried the payment reference at the top level, but the webhook only looked for it in the order fields, so a capture that completed later was dropped and the payment waited for a manual recheck. Fixed by my PR, merged 30 Oct into the development branch, not yet released. PR #4275
- Bagisto · Razorpay: the order amount was truncated instead of rounded, so totals like ₹19.99 were charged but no order was placed. Fixed by my PR, merged 13 Oct. #11523 · PR #11524
- Paid Memberships Pro · Stripe: the webhook answered 200 when re-fetching the event from Stripe failed, so Stripe never redelivered it. Fixed by my PRs, merged 14 and 15 Oct; the second covers scheduled webhook runs. #3889 · PR #3890 · PR #3898
- FOSSBilling · Stripe: subscription renewals were never recorded after the first invoice, so Stripe charged the customer and the renewal invoice stayed unpaid. Fixed by my PR, merged 16 Oct. #4522 · PR #4523
- FOSSBilling · Stripe currencies: in COP, HUF, IDR, ISK, PKR, UGX and seven other currencies the total is sent to Stripe in the wrong unit, so the customer is charged 1/100 and the invoice is marked paid. Fixed by my PR, merged 17 Oct. #4540 · PR #4541
- LNbits · fiat payments: a fiat invoice was failed after one hour while the provider's checkout was still payable, so a later payment was never credited. Fixed by my PR, merged 23 Oct into the development branch, not yet released. #4245 · PR #4246
- PayU for WooCommerce: a COMPLETED payment notification was answered 200 but no longer completed the order, so the paid order stayed on hold or was cancelled as unpaid. Fixed by my PR, merged 23 Oct on the main branch, not yet released. #121 · PR #122
- Paid Memberships Pro · Payfast: the payment notification was answered 200 before it was validated, so when the validation request to Payfast failed, Payfast never sent it again and the paid checkout was left unfinished, with no membership. Fixed by my PR, merged 27 Oct, released in 1.8: the notification now gets 503 so Payfast re-sends it. #113 · PR #114
- Invoice Ninja · Razorpay: the Razorpay webhook handler is an empty stub, so when the customer closes the tab before the checkout posts back, Razorpay captures the payment but Invoice Ninja never records it and the invoice stays unpaid. Fixed by my PR, merged 29 Oct, released in 5.13.51 on 30 Oct. #13394 · PR #13397
- Fider · Stripe billing: when the first charge of a new subscription was declined and paid later, the payment was ignored, so the customer was charged every month and the site stayed on the free plan. Fixed by the maintainer on 4 Nov on the main branch, not yet released: a subscription that leaves “incomplete” now activates the site. #1740 · fix #1760
- Charitable · PayPal Standard: when the postback that verifies an IPN with PayPal gets no answer at all, the listener still answers 200, so PayPal stops resending and the donation stays pending although the donor has paid. Fixed by the maintainers on 28 Oct, released in 1.8.14: an unanswered or non-2xx verification postback now answers 503, so PayPal re-sends the notification, while an INVALID answer still gets 200. Checked against the released code. forum topic
- SumUp for Vendure: the pending fix waiting for the next release made adding a SumUp payment fail on every attempt, and the release that fixed amounts being charged 100 times too high had never reached npm. Fixed by the maintainer within a day, released in 0.3.1 on npm on 28 Oct. #48
- Adyen for Magento 2 · split payments: the cause of “Full order amount has not been authorized”: authorised amounts were compared at a different precision than they are stored. Fixed by Adyen on 28 Oct on the main branch, not yet released: the amounts are now compared in minor units. Adyen closed my PR in favour of this fix. #3352 · PR #3379 · fix #3397
- Nexi Checkout for WooCommerce: the webhook is answered 200 at once and settled by one background job; if that job's status request to Nexi fails, nothing retries, so a Swish payment whose buyer didn't return to the shop is cancelled although the customer was charged. Fixed by the maintainers on 22 Oct, released in 2.14.9 on 27 Oct: a failed status request is now retried with a growing delay, and an order already paid in Nexi is no longer cancelled. #367
- Vipps MobilePay for WooCommerce · subscriptions: when the response to creating a renewal charge was lost, the renewal was marked failed, but Vipps still took the charge and its webhook found no order, so the subscription went on hold. Fixed by the maintainer on 22 Oct, released in 6.3.4 on 26 Oct. Checked against the fix: the renewal now stays pending and is paid once the charge is confirmed. #420
- Invoice Ninja · SEPA, BACS, ACH, GoCardless: a subscription whose payment started as pending was never completed, so no recurring invoice followed. Fixed by the maintainers on 22 Oct, in the next release. #13343
- BTCPay for WooCommerce: when the plugin cannot re-fetch a settled invoice from BTCPay Server, the webhook is still answered 200, so BTCPay never redelivers it and the paid order stays on hold. Fixed by the maintainer on 20 Oct, released in 2.8.6: the webhook now answers 503 so BTCPay redelivers it. #93
- Bagisto · PayPal Standard: a buyer who paid but didn't return to the store got no order, and every retry of PayPal's notification failed with 500. Fixed by the maintainers on 15 Oct, listed in the changelog. #11531
- Invoice Ninja · Stripe iDEAL, Bancontact, Klarna: no payment was recorded when the customer didn't come back from the bank. Fixed by the maintainers on 12 Oct. #13341
- django-payments · Sage Pay: the return route crashed on every real redirect, so no payment was ever confirmed. Fixed by the maintainer on 11 Oct. #499 · PR #500
- Odoo · Mollie: a failed status request to Mollie was acknowledged with 200, so the transaction stayed in draft. Fixed by Odoo on 8 Oct. #290678 · fix · case
Not counted above, since someone else reported the bug: in Standard Webhooks, the webhook signing spec, the Python library's sign() signed the wrong timestamp for a timezone-aware datetime outside UTC, so the receiver rejected every such webhook. Fixed by my PR, merged 28 Oct. PR #334
Confirmed, fix in progress (5)
- Mollie for WooCommerce: the REST webhook answers 200 when the payment status can't be fetched, so Mollie stops retrying and paid orders stay pending. Confirmed by Mollie; they are preparing a patch. #1304 · case
- Medusa · Stripe: the webhook signature is checked when the queued job runs, so a delivery already answered 200 is dropped if the job starts more than five minutes after Stripe signed it. My PR passed Medusa's automated review; a new rule closed it until the issue is assigned, which I have asked for. #17261 · PR #17262
- Formidable Forms · PayPal: a capture that PayPal declined or left pending inside a completed order is saved as a complete payment, and the form's Successful Payment actions run. Formidable added it to the 7.1 milestone (2 Nov). #3617
- Hexclave (formerly Stack Auth) · payments: a subscription bought through a purchase URL for a custom customer is recorded as a team’s, so the customer is charged every month, never gets the product, and can be sent through checkout and charged for it again. Found by reading the code, not reproduced. Hexclave opened a fix on 3 Nov, not yet merged. #2131 · fix #2145
- LatePoint · Razorpay: since 5.6.11 the webhook no longer saves the payment id before creating the booking, so a customer who pays but doesn't come back to the booking form is charged, and every delivery of the captured payment is answered 400 with no booking. LatePoint says the next update will change how the Razorpay payment.captured webhook completes these bookings (6 Nov). forum topic
Reported, waiting for the maintainers (47)
- Spree PayPal Checkout 0.7.1 · Spree 5.x: a PayPal capture that is still pending or was declined marks the Spree order paid, and a later denial can't undo it. With a gift card or store credit on the order, PayPal charges the full order total, so the buyer pays the covered part twice. Found by reading the code, not reproduced. Fixed in the new PayPal provider for Spree 6.0, reported for the 5.x gem. #20
- PAYONE for Magento 2 · Prepayment: cancelling an unpaid Prepayment order in Magento leaves it payable at PAYONE, and when the transfer arrives later the plugin moves the cancelled order to Processing and, with automatic invoicing on, to Complete with an invoice for the shipping only, so the customer has paid, the items stay cancelled and the order reads as done. Found by reading the code, not reproduced. #639
- MotoPress Hotel Booking · PayPal: when the IPN check with PayPal fails, the listener still answers an empty 200, so PayPal doesn't resend it, and a payment confirmed after the pending time is dropped, so a guest who paid loses the booking and the room goes back on sale. Reported on the WordPress.org support forum: the plugin has no public issue tracker. forum topic
- Merx · Stripe iDEAL: until the buyer comes back from the bank the order exists only in their session, so a buyer who pays with iDEAL and doesn't return is charged, the webhook finds no order and answers 200, and the shop never gets the order. #89
- Zen Cart · PayPal RESTful: when a webhook fails with 500 so that PayPal retries, its event id is already recorded, so the retry is answered 200 as a duplicate and the event is never handled. #51
- WP User Frontend · PayPal: when the plugin's own request to PayPal to verify a webhook fails, the delivery is still answered 200, so PayPal never resends it and a recurring pack, or a one-time payment whose capture reply was lost, is charged but never granted. PR #1872 (comment)
- solidus_stripe: when the buyer pays but never comes back to the store, the webhook completes the payment and leaves the order unplaced, and paying again in the same session charges the card a second time. #339 · PR #340
- LearnPress · PayPal subscriptions: the subscription webhook answers 200 to every error, including a timed-out signature check, so PayPal never re-sends a renewal or activation that failed. #650
- Lago · Flutterwave: when the call that verifies a completed charge fails, the job ends as if nothing happened and nothing retries it, so the paid invoice stays pending. #6974
- Formance Payments · payment initiations: when a payout’s outcome arrives by webhook the payment initiation is never updated, and the polling update is stamped with an older time than “processing”, so a failed payout keeps reading as processing. #839
- Lago · Adyen chargebacks: every chargeback notification job fails on parsing, and the payment is looked up by the dispute’s reference instead of the payment’s, so lost disputes are never recorded on the invoice. #6960
- Liberapay · Stripe transfers: when the transfer to the creator fails inside the Stripe webhook, it is left pending and the webhook still answers 200, so nothing retries it: the donor is charged, the creator is not paid and the donation stops renewing. #2827
- Formance Payments · Column: every event of a transfer is stamped with the transfer’s creation time, so an older event that Column retries after newer ones sets a returned payment back to pending. #838
- GiveWP · Stripe: when GiveWP cannot fetch the event back from Stripe, the webhook still answers 200, so Stripe never resends it and a paid donation stays “processing”. #8528
- Open Collective · Stripe SEPA/ACH/Bacs: changing the amount of a recurring contribution while its bank debit is still processing removes the only link to that payment, so when the debit settles the webhook finds nothing, answers 200, and the contributor has paid with no transaction recorded. #9041
- Saleor · Stripe app: a brief Stripe error while the storefront processes a payment is recorded as a final failed charge, and Saleor then ignores the success from Stripe’s webhook because it is older, so the customer is charged and the transaction shows nothing charged. #2448
- Ghostfolio · Premium via Stripe: Premium is granted only when the buyer’s browser comes back through Stripe’s success redirect; there is no webhook, so a buyer who closes the tab after paying is charged and stays on Basic. Found by reading the code, not reproduced. #8318
- Mercado Pago for WooCommerce: the merchant_order IPN adds a flat 1.00 for each payment instead of that payment’s coupon amount, so an order paid with a Mercado Pago coupon is left pending and a small order can be marked paid on money that never arrived. Reported on the WordPress.org support forum: the plugin takes no GitHub issues. forum topic
- Mercado Pago for WooCommerce · cancelled orders: a payment approved after its order was cancelled, such as a boleto paid late or a Checkout Pro payment made after WooCommerce cancelled the unpaid order, is answered with 200 and saved in the order data, but the order stays Cancelled and gets no note. Reported on the WordPress.org support forum: the plugin takes no GitHub issues. forum topic
- Nuvei Payments for WooCommerce: with classic checkout, an alternative payment approved after WooCommerce has cancelled the unpaid order is answered with 200 and dropped, so the shopper is charged and the order stays Cancelled with no note. Found by reading the code, not reproduced. #19
- Dokploy Cloud · Stripe billing: after a failed renewal the billing page only offers a new subscription, and once the owner pays it, Stripe's retries of the old one switch all of their servers off again. Found by reading the code, not reproduced. Labelled as a bug by the maintainer. #5770
- dj-stripe · Stripe subscriptions: since Stripe API 2025-03-31 the billing period is on the subscription items, which dj-stripe doesn't read, so the access check it documents treats a paying subscriber as expired. #2252 · PR #2253
- Contact Form 7 · Stripe: when a paid submission is not accepted (a quiz or CAPTCHA on the form, a field edited after the first step, a failed e-mail), the paid PaymentIntent is dropped or marked as used, so the buyer is asked to pay again or the paid submission is rejected as spam. Reported on the WordPress.org support forum: the plugin takes no GitHub issues. The plugin's author is looking into it. forum topic
- Paid Memberships Pro · PayPal: when PayPal completes the order but holds the capture for review or declines it, checkout completes anyway, so the member gets the level with no money behind it, and the later denial isn't handled. #21 · PR #22
- Formance Payments · Column: webhooks for manually approved or rejected transfers are checked against another endpoint's signing secret and answered 500 on every retry, so Column drops them. #835
- Liberapay · PayPal: when PayPal's answer to a capture is a 500 or a timeout, the payment is marked failed or left unread, so a retry by the donor can charge twice and a capture that went through may never be recorded. #2731 (comment)
- HCB (Hack Club) · recurring donations: when Stripe delivers the same invoice.paid event again, a second donation is recorded for the one payment, with a second ledger credit and a second payout. #15398 · PR #15399
- Paytrail for WooCommerce · manual invoice activation: when the payment-status request that comes before activating a Walley or Klarna invoice fails, the order is completed as if there were nothing to activate, so the invoice is never activated and nothing on the order says so. The maintainers are looking into it. #247 · PR #248
- GoCardless for WooCommerce · Pay by Bank: when the bank's answer is still pending at the buyer's return, only a background job attaches the payment; if its one request to GoCardless fails, nothing retries, and the paid order is cancelled. #208
- Paystack for WooCommerce: when the plugin's verify request to Paystack fails inside the webhook, the delivery is still answered 200, so Paystack never resends it and the paid order is cancelled. #147 (comment)
- Flutterwave for WooCommerce: the webhook records a transaction as processed before verifying it, so when verification fails the retry is discarded as a duplicate and the paid order is cancelled. #105
- stripe/sync-engine: when writing a batch of webhook events to Postgres fails, the batch is dropped after Stripe has already been answered 200, so a paid invoice stays open in the database. #353
- Amazon Pay for Magento 2: with “Charge when order is placed”, a capture that Amazon declines is still invoiced as paid at checkout, and the later Declined notification is skipped as a duplicate. #1304
- Pay. for Magento 2: when the plugin's status request to Pay. fails, the payment notification is still answered TRUE, so Pay. never retries it and the paid order is cancelled. #248 · PR #249
- Checkout.com for WooCommerce: in classic mode a 3-D Secure payment is linked to the order only when the buyer comes back to the shop, so if they don't, every webhook for the captured payment is rejected and the paid order is cancelled. #431
- Akaunting · PayPal Standard: the payment notification is checked with PayPal using an empty request, so PayPal answers INVALID every time and no PayPal payment is recorded. #8 · PR #9
- Lunar · Stripe: when listing the payment's charges from Stripe fails once, the paid order is not placed and the payment is marked processed, so no retry places it. #2781
- Payfast for WooCommerce: when the plugin's validation request to Payfast fails, the payment notification is still answered 200, so Payfast never re-sends it and the paid order is cancelled. #519
- EverShop · Stripe refunds: a refund made in EverShop is recorded a second time when Stripe's refund notification arrives, so the order shows twice the refunded amount and a full refund sends the customer a second email. #1112
- Paymenter · Stripe SEPA Direct Debit: when a SEPA payment succeeds after the daily cron has cancelled the unpaid order, the service is marked active but the server is never created. #1378 · PR #1381
- WooCommerce PayPal Payments · iDEAL and other local methods: when the fee lookup after the capture fails, the webhook still answers 200, so the order stays pending and is later cancelled although PayPal captured the payment. #4798 · PR #4799
- Laravel Cashier Mollie: the webhook answers 200 when fetching the payment from Mollie fails, so a paid first payment never starts the subscription. #330 · PR #331
- Odoo · Mercado Pago: the webhook answers 200 when fetching the payment from Mercado Pago fails, so it stops retrying. #293901
- django-paypal: when a receiver raises, PayPal's retry of the same message is flagged as a duplicate and acknowledged, so the payment is never processed. #299
- django-oscar-paypal: a pending or declined PayPal capture places the order as paid. #302
- Razorpay for WooCommerce: with the Payment Action set to “Authorize”, the webhook cron marks orders of authorized payments Failed. #670 · case
- WooCommerce Stripe Gateway: a webhook that fails signature validation is answered 204, so Stripe never retries and the order stays pending. #4150 · case
Your integration
The same checks, run read-only on your logs and database: callback delivery audit. Email: hello@terminalstate.dev.