WooCommerce PayPal payments not working: how to fix it

WooCommerce PayPal payments not working? Check sandbox mode, webhooks, currency, caching, CSP and plugin clashes to get checkout taking money again.

Mohit Goyal11 min read
WooCommerce PayPal payments not working: how to fix it

When WooCommerce PayPal payments stop working, it's almost always one of five things. The PayPal Payments plugin is in sandbox mode or has stale credentials, PayPal's webhooks can't reach your site, the order currency isn't supported for your account, the PayPal Smart Button script is being blocked by caching, minification or a Content Security Policy (CSP), or a checkout plugin is clashing with PayPal's scripts. Turn on PayPal Payments logging, open the browser console on your checkout page, and the error will usually point you at one of these pretty quickly.

Some failures, like INSTRUMENT_DECLINED, are the buyer's bank saying no. Those aren't your store's fault at all.

Here's the order I check things in when a store is losing PayPal sales and nobody can say why.

How do I find out why WooCommerce PayPal payments are not working?

Get the logs and the console open before you touch a single setting. If you start toggling things at random, the real error gets buried under the new ones you've just created.

  1. 1

    Turn on logging

    In the WooCommerce PayPal Payments settings, enable Logging. Every PayPal API request is then logged with a Debug ID.

  2. 2

    Read the latest log

    Go to WooCommerce > Status > Logs and open the newest woocommerce-paypal-payments file. Copy the error codes and Debug IDs.

  3. 3

    Open the browser console

    On the checkout page, press F12. Red Content Security Policy errors in Console, or failed js?client-id= or ppc-create-order requests in Network, show where it breaks.

  4. 4

    Check failed order notes

    WooCommerce records PayPal's reason on the order. Make sure it's really the error you think it is.

  5. 5

    Test as a guest

    Repeat the checkout in a private window while logged out. Page caching usually only affects visitors, not admins.

The Network tab tip comes from the plugin's own advanced troubleshooting guide. Grab your Debug IDs now if there's any chance you'll need PayPal support, because they expire after roughly 48 hours.

Once you've got an error message, match it to a likely cause here:

Symptom or errorMost likely causeFirst thing to try
No PayPal button at allScript blocked by CSP, minification or page cacheCheck the console, exclude PayPal scripts, purge cache
Popup opens, then closesCheckout plugin refreshing the page, JavaScript conflictTest with the checkout plugin switched off
"The payee does not have a PayPal account"Invalid credentials or unverified PayPal accountDisconnect and reconnect via onboarding
"Something went wrong. Please try again…"API rejection, plugin conflict or blocked REST endpointRead the log for the real PayPal error
CANNOT_MIX_CURRENCIES or UNPROCESSABLE_ENTITYMulti-currency plugin or unsupported currencyCheck the order currency against PayPal's list
DUPLICATE_INVOICE_IDRestored backup or two sites sharing an invoice prefixGive each site a unique invoice prefix
Paid at PayPal, order stuck on pendingWebhooks not arrivingResubscribe webhooks, check firewall rules
INSTRUMENT_DECLINED or PAYMENT_DENIEDBuyer's bank, card or PayPal accountNot a store fault; ask the buyer to use another method

Most of that table comes from the plugin's common errors page. The rest is what I cover below.

Is PayPal connected in sandbox or live mode?

Check this first. It takes ten seconds, and a store left in sandbox mode takes no real money. The Connection tab of WooCommerce PayPal Payments has a Sandbox checkbox that switches the plugin between live and sandbox accounts. If someone tested the store and forgot to switch it back, buyers get an error or a test login page.

"The payee does not have a PayPal account" usually means, according to the WooCommerce PayPal team, that the API credentials are invalid or the merchant account isn't verified. Reconnecting through the onboarding wizard often sorts it. If it doesn't, only PayPal Merchant Support can confirm the account's verification status. And if you're not sure the credentials and webhooks are in sync, the plugin's support team suggests disconnecting and onboarding again from scratch with "Start over".

Staging sites cause their own trouble. Run a staging copy on the same PayPal account, or restore an older backup, and PayPal can reject orders with DUPLICATE_INVOICE_ID because it's seeing an invoice number it already knows. Don't turn off PayPal's duplicate protection. Give every site on your PayPal account a unique invoice prefix instead.

Are PayPal webhooks reaching my site?

If orders sit on pending after buyers have paid, the webhooks probably aren't getting through. WooCommerce PayPal Payments uses webhooks rather than the old IPN system, and for alternative payment methods the payment is only captured after a webhook confirmation arrives. No webhooks means money can leave the buyer's account while the order stays pending, and refunds you make in PayPal never show up in WooCommerce.

Click Resubscribe in the webhook section of the plugin settings. Don't trust the Simulate button to tell you it worked. A GitHub issue reports the Simulate button doing nothing since version 3.3.1, so don't rely on it: it may show a false failure, or a false success left over from an earlier run. A small real payment and refund with logging on is a much better test.

When webhooks keep failing, something is normally in the way:

  • A firewall, Cloudflare WAF rule or security plugin blocking /wp-json/ requests. WooCommerce lists a blocked REST endpoint as a known cause.
  • Maintenance mode, password protection or HTTP basic auth on the live site.
  • A domain or host change. Webhooks keep pointing at the old URL until you resubscribe.

If PayPal broke right after a host move or DNS change, rule that out before anything else. I do these moves as part of my hosting migration and maintenance work, and payment webhooks belong on any migration go-live checklist next to DNS and email.

Is my store currency supported by PayPal?

Not every currency works for every PayPal account, and an order in an unsupported or mixed currency gets rejected. PayPal's supported currencies reference says BRL, CNY and MYR only work for in-country accounts. HUF, JPY and TWD don't support decimals, so amounts in those have to be sent as whole numbers. WooCommerce's currency documentation also points out that PayPal supports merchants in some countries, India for example, without supporting the local currency. So if your Indian store prices in rupees, check that before anything else. For domestic Indian checkouts I'd usually make Razorpay the main gateway anyway.

Multi-currency plugins are the other usual suspect. PayPal rejects an order when the line items, shipping and total aren't all in the same currency. The error is CANNOT_MIX_CURRENCIES, and it tends to arrive wrapped in UNPROCESSABLE_ENTITY. WPML documented a case where PayPal Payments 2.9.1 failed every order placed in a non-default currency. I built Wow Vastra with a currency switcher and worldwide checkout, and on a store like that you need to test every gateway in every currency the switcher offers. No shortcuts.

Rounding causes smaller, sneakier failures. Tax or discount plugins can leave WooCommerce's total a penny off the sum of its line items. The plugin has a Subtotal Mismatch Behavior setting that sends PayPal an extra line to cover the difference.

Are caching, minification or a CSP blocking the PayPal buttons?

If the PayPal button has vanished completely, this is where I look first. WooCommerce's own docs say caching or JavaScript minification can break PayPal Payments. They recommend excluding at least /woocommerce-paypal-payments/modules/ppcp-button/assets/js/button.js from minification and purging the cache after every plugin update. If you use WP Rocket, its minify, combine and delay-JavaScript options are the first place PayPal exclusions should go. There are WordPress.org threads where WP Rocket stopped the button showing.

Full-page caching has a newer problem too. A GitHub issue reported in 4.2.0 says that with SDK v6, a cached page older than the WordPress nonce lifetime (12 to 24 hours) can fail its token request with "Could not validate nonce", and no buttons render. Until that's resolved, keep pages with PayPal buttons out of the page cache, or set the cache lifetime shorter than the nonce lifetime. The 4.2.0 changelog also fixed buttons disappearing after several page loads, so make sure you're on the current version.

Then there's CSP. A policy that doesn't list PayPal blocks its script outright. PayPal's button troubleshooting page shows the console error you'll get: "Refused to load the script https://www.paypal.com/sdk/js". Their suggested allow-list looks like this:

text
script-src 'unsafe-inline' https://*.paypal.com https://*.paypalobjects.com;
style-src 'unsafe-inline' https://*.paypal.com;
connect-src https://*.paypal.com;
frame-src https://*.paypal.com;
img-src https://*.paypal.com https://*.paypalobjects.com;

Be aware that 'unsafe-inline' in script-src weakens the policy, because it lets any inline script run. Where your site supports it, use nonces or hashes instead, and test in report-only mode before you enforce the policy.

Merge these into your existing policy rather than replacing it. I wrote and maintain HTTP Security Header, a WordPress.org plugin with 1,000+ active installs that adds CSP and other headers from a settings screen. That work has taught me a strict CSP written without payment providers in mind is one of the quickest ways to make checkout buttons disappear. Run your checkout URL through my free Security Headers Checker to see exactly what policy you're sending, and read my post on fixing a CSP that broke WordPress for how to test safely in report-only mode.

Don't just delete the CSP

Removing your security headers brings the PayPal button back, but it leaves the checkout exposed. Add the PayPal domains to the right directives instead, and test in report-only mode first.

Is a checkout plugin like Fluid Checkout clashing with PayPal?

It can be. Checkout plugins rebuild the page that PayPal's scripts expect to find. Fluid Checkout's changelog lists fixes for WooCommerce PayPal Payments, including switching to the classic checkout context so scripts work and removing a duplicate place-order button. Its developer has also described PayPal popups closing suddenly on mobile because the checkout refreshed parts of the page as the popup opened. The usual fix is to update both plugins and retest; you rarely need to remove either one.

To confirm a conflict without breaking checkout for real customers, use the Health Check & Troubleshooting plugin. WooCommerce's guide recommends it because it disables plugins only for you. Test with only WooCommerce and PayPal Payments active, then switch the others back on one at a time.

Custom checkout code can clash as well. If a required checkbox is validated on the woocommerce_checkout_process hook, the PayPal popup opens even when the box is empty, because that hook runs only after the PayPal order is created. Move the check to woocommerce_after_checkout_validation and it behaves. I built the optimised checkout for the Nortek LED store, and hook order is one of the details worth checking on any custom checkout.

Which PayPal errors are not my store's fault?

INSTRUMENT_DECLINED and PAYMENT_DENIED come from the buyer's bank or from PayPal, and no WooCommerce setting will change them. INSTRUMENT_DECLINED means the buyer's card, bank or credit line was refused, and the plugin sends the buyer back to pick another funding source. PAYMENT_DENIED is usually about the buyer's PayPal account or PayPal's risk review, and PayPal won't tell you why. A low background rate of both is normal. I'd only escalate if declines spike without a change in traffic, cluster on one method such as Pay Later, or if PayPal shows a payment as approved while WooCommerce marks the order failed.

What should I ask a developer to check?

Ask them to go through mode and verification, webhooks, currency, caching, CSP and plugin conflicts, in that order. Specifically:

  • live or sandbox mode, and that the merchant account is verified
  • webhook delivery, tested with a real payment and refund
  • the store currency against PayPal's list, in every currency your switcher offers
  • cache, minify and delay-JS exclusions for PayPal scripts
  • your CSP on the cart, checkout and product pages
  • conflicts, tested on staging or in Health Check mode, never on live customers

If Stripe is failing too, the cause is probably shared, and it's usually caching or CSP. My Stripe checkout fix guide covers that side.

Need your PayPal checkout fixed today?

If PayPal is failing right now, send me your store URL, the latest PayPal Payments log and a screenshot of the console error through my contact page. I'll look at the cause and tell you what it will take to fix. If you'd rather it didn't happen again, my WooCommerce store work and maintenance retainers cover updates, so plugin updates are tested before they reach your live checkout.

Frequently asked

Why is the PayPal button not showing on my WooCommerce checkout?+

Usually something is blocking the PayPal script. JavaScript minification, delay-JS options, an old page cache or a Content Security Policy that doesn't allow paypal.com domains can all hide the button. Check the browser console for red errors, exclude the PayPal scripts, then purge the cache.

Why do my WooCommerce orders stay on pending after a customer pays with PayPal?+

WooCommerce PayPal Payments relies on webhooks to confirm some payments. If a firewall, security plugin or domain change stops PayPal's webhooks reaching your site, the orders never update. Resubscribe the webhooks in the plugin settings and test with a small real payment and refund.

What does CANNOT_MIX_CURRENCIES mean in WooCommerce PayPal Payments?+

It means PayPal received an order where the items, shipping and total weren't all in the same currency. It usually comes from a multi-currency or currency switcher plugin, so test PayPal in every currency the switcher offers.

How do I fix 'The payee does not have a PayPal account' in WooCommerce?+

This error usually means the API credentials are invalid or the PayPal business account isn't verified. Disconnect the PayPal Payments plugin, choose Start over and reconnect through the onboarding wizard. If it still appears, ask PayPal Merchant Support to confirm your verification status.

Is a PayPal INSTRUMENT_DECLINED error a problem with my WooCommerce store?+

No. It means the buyer's card, bank or credit line refused the payment, and WooCommerce PayPal Payments sends the buyer back to choose another funding source. Only dig into it if declines suddenly spike.

Can Fluid Checkout or another checkout plugin break PayPal payments in WooCommerce?+

Yes. Checkout plugins change the page that PayPal's scripts expect, and Fluid Checkout has shipped several compatibility fixes for WooCommerce PayPal Payments. Update both plugins, then test with the checkout plugin disabled to confirm the conflict.

Mohit Goyal

Written by Mohit Goyal

Senior Web Developer in Gurugram, India. 100+ fast, SEO-friendly sites shipped in 4+ years with Next.js, React and WordPress, including the procol.ai rebuild. Send me your next project.

Keep reading

WooCommerce Razorpay payments failing: how to fix it

WooCommerce Razorpay payments failing? Check the webhook, Payment Action, caching and cron, and recover paid orders wrongly marked Failed.

10 min read

WooCommerce Stripe payments failing: how to fix checkout

Stripe payments failing on WooCommerce? How to tell a card decline from a broken checkout, and fix webhooks, 3D Secure, currency, caching and plugin bugs.

10 min read

Let's build

Have a site that needs to be fast, rank and convert?

Open to Work. Usually replies within a day.