TL;DR: FedEx permanently shut down its legacy SOAP Web Services on June 1, 2026.
Any integration still depending on those endpoints stopped getting FedEx rates.
What surprised me was not the migration itself. It was the way the failure showed up.
The stores I saw did not crash. They did not throw an obvious error. Their uptime monitors stayed green.
They simply stopped showing FedEx shipping rates at checkout.
And in some ways, that is a much worse failure than a site going down.
A little context before I get into it.
I work on the business and support side of WooCommerce shipping plugins, which means I spend quite a bit of time reading tickets from merchants when something suddenly stops working.
So this is less of a migration tutorial and more of an observation from the merchant side of an API shutdown.
You should absolutely compare it with your own logs and implementation.
But I think there is an interesting reliability problem here that goes beyond FedEx.
What FedEx switched off
FedEx retired its legacy SOAP Web Services in favour of its REST APIs.
There were two important deadlines:
March 31, 2026 for software providers and platforms
June 1, 2026 for merchants using their own FedEx credentials
After those dates, the old SOAP integrations were no longer something you could keep running indefinitely.
And this was not simply a matter of changing the API URL.
Authentication changed too.
The old SOAP integration sent things like the key, password, account number, and meter number with the request.
REST uses OAuth 2.0 client credentials instead.
That means there is now a token lifecycle involved:
curl -s -X POST https://apis.fedex.com/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=$FEDEX_API_KEY" \
-d "client_secret=$FEDEX_SECRET_KEY"
No access_token means nothing downstream is going to work.
The APIs themselves also changed shape.
Rating, tracking, labels, freight, and other services moved into different REST resources, with different request and response structures.
So for a deeply integrated application, this was not really "replace SOAP with REST."
There is parsing logic to rewrite, service mappings to check, authentication to change, and edge cases to retest.
There is also one very non-technical problem: getting the new credentials usually requires access to the merchant's FedEx account and MFA.
That matters more than it sounds.
A developer cannot always complete this migration alone.
Someone who actually controls the FedEx account has to participate, and on a small WooCommerce store that person may be the store owner who has no idea an API migration is happening in the first place.
The strange part: nothing actually crashed
This was the part that caught my attention.
Imagine a WooCommerce shipping method calls FedEx and gets no usable rates back.
What should happen?
From the store's point of view, "no rates" is not necessarily an exception.
Sometimes there genuinely are no available services for a package or destination.
So the shipping method can return an empty array.
WooCommerce continues rendering the checkout.
The page still loads.
The request still returns HTTP 200.
Your uptime monitor sees: Everything looks good.
Meanwhile the customer sees: No FedEx shipping option.
That is a very different kind of outage.
The application is technically alive, but an important part of the business is no longer functioning.
The fallback-rate problem is even worse
Now imagine the store also has a flat-rate shipping method configured as a backup.
The FedEx rates disappear.
But checkout still works.
Orders keep coming in.
From the merchant's perspective, the site looks completely normal.
Except every order is now being priced using a flat rate someone may have configured months or years ago.
Maybe that number is still close enough.
Maybe it is not.
The store can quietly lose money on every shipment without generating a single obvious technical failure.
That is why I think this type of problem can be more damaging than a crash.
A crash is loud.
Someone notices.
A monitor fires.
A customer complains.
People start looking at logs.
A missing shipping rate can continue for days because almost every layer of the system is technically doing what it was designed to do.
"No service" and "dead upstream" look surprisingly similar
This is the reliability problem I keep coming back to.
From the application side:
FedEx doesn't service this shipment
and
FedEx integration is completely broken
can both eventually become:
[]
That is not a lot of information to work with.
If your monitoring only watches exceptions, HTTP status codes, and page availability, you may never see the failure.
So if I were building or maintaining one of these integrations, there are a few things I would want.
1. Monitor missing rates, not only errors
Your exception handling may be working perfectly.
The problem is that an empty rate response never reaches it.
You need to pay attention to the absence of a result too.
For example, even a basic WooCommerce logger can help:
<?php
/**
* Warn when a package has no available shipping rates.
*
* Logs to WooCommerce > Status > Logs
* Source: shipping-watch
*/
add_filter(
'woocommerce_package_rates',
function ( array $rates, array $package ): array {
if ( empty( $rates ) ) {
wc_get_logger()->warning(
sprintf(
'No shipping rates for package to %s %s',
$package['destination']['country'] ?? 'unknown',
$package['destination']['postcode'] ?? ''
),
[ 'source' => 'shipping-watch' ]
);
}
return $rates;
},
99,
2
);
A few empty results are probably normal.
If suddenly almost every checkout starts producing them, that is much more interesting.
I would rather find that out the same day than discover it from a merchant support ticket two weeks later.
2. Be careful with cached rates while debugging
Shipping rates are often cached, and normally that is exactly what you want.
During an API migration, though, caching can make troubleshooting confusing.
You can change credentials or break an API connection and still see an older successful rate for a while.
That creates the comforting impression that everything is working.
When diagnosing a problem, make sure you know whether you are looking at a live carrier response or a cached result.
In WooCommerce, enabling shipping debug mode temporarily can help while testing:
add_filter( 'woocommerce_shipping_debug_mode', '__return_true' );
Do not leave debugging changes around unnecessarily, but during a migration I want as little ambiguity as possible.
3. Test authentication directly
A checkout is a terrible diagnostic tool.
There are too many layers between the carrier API and what eventually appears on screen.
If authentication is the dependency everything else sits on, test authentication directly.
For FedEx REST, that means verifying that the OAuth request successfully returns an access token.
That is also something you can monitor automatically.
If getting a token suddenly fails, I would much rather receive an alert for that specific problem than wait until someone notices that shipping disappeared from checkout.
4. Put migration warnings where the merchant actually works
This one is less technical, but I think it matters.
API providers send migration emails.
The problem is that merchants receive a lot of emails.
Carrier announcements, pricing changes, service notifications, promotions, account notices...
It all blends together.
And the person reading those emails may have no idea that "SOAP Web Services retirement" translates into:
Your WooCommerce checkout may stop showing FedEx rates.
If you maintain an integration, an admin notice inside the application can be much more effective:
Action required: Your FedEx integration uses a legacy API that stops working on June 1. Update your credentials before that date or FedEx rates may disappear from checkout.
That is much harder to misunderstand.
What worked better on the stores that migrated
The obvious first step was moving to an integration that talks to the FedEx REST APIs natively rather than continuing to depend on the retired SOAP services.
That is also how the FedEx Shipping PRO plugin I work with is built, so take this section with the appropriate amount of bias.
But there are a few design decisions in it that I think are useful regardless of which FedEx integration you use.
One is failure isolation.
Parcel and freight are handled as separate adapters. If a freight request fails, that does not automatically mean your regular FedEx Ground or Express rates need to disappear too.
That sounds like a small implementation detail until something upstream breaks.
Another is having a way to test the integration without using the WooCommerce checkout as your debugging tool.
For example:
wp wc-fedex-shipping status
shows the current FedEx configuration and shipping instances.
wp wc-fedex-shipping validate
runs configuration checks and reports what is passing or failing.
And you can request a live rate directly:
wp wc-fedex-shipping rates quote \
--products=9405 \
--destination="123 Main St, New York, NY 10005, US"
For me, this is one of the biggest lessons from the SOAP shutdown.
A shipping integration should not only be able to return rates when everything is working.
It should also help you understand why rates are missing when something is not.
That is a much better experience than repeatedly refreshing checkout and guessing whether the problem is the address, the products, the shipping zone, the credentials, or FedEx itself.
If you are still using an older FedEx integration, this is also a good reason to check whether it actually uses the current REST APIs rather than assuming an installed plugin is still compatible just because WooCommerce itself is working.
There is a free version of our FedEx Shipping PRO plugin on WordPress.org if you want to test the REST integration on a WooCommerce store:
And if you need more advanced FedEx functionality, the PRO version is built on the same REST-based integration.
I would still rather people test the free version themselves than take my word for it.
This is not really a FedEx problem
FedEx announced the migration well in advance.
The documentation existed.
The deadline was public.
So I do not think the interesting lesson here is:
FedEx turned off an old API.
APIs get retired. That is normal.
What interested me was how many systems between the dead API and the merchant could continue behaving "correctly."
The carrier returned no usable rate.
The shipping integration returned no shipping option.
WooCommerce rendered the checkout.
The web server returned 200.
The uptime monitor stayed green.
Every individual layer could look healthy while the business function they were supposed to support was broken.
That is the part worth thinking about.
We spend a lot of time monitoring failures that produce errors.
Maybe we should spend more time monitoring expected things that suddenly stop happening.
Orders.
Payments.
Shipping rates.
Emails.
Webhooks.
Background jobs.
Sometimes the absence of an event is the actual incident.
If you have worked on shipping, payments, or another API where an empty response can be both completely legitimate and a sign that the upstream service is dead, I would be interested to know how you monitor it.

Top comments (0)