Fix Magento USPS AC-15210: v3 REST Replacement
If your Magento 2 store stopped showing USPS shipping rates in January 2026, you hit AC-15210. The built-in Magento_Usps module calls the USPS Web Tools XML API — which was retired on January 25, 2026. That API no longer exists. No patch will fix it because the entire transport layer needs to be replaced.
This guide walks through the drop-in fix: a new carrier module (RevAddress_USPSv3) that uses the USPS v3 REST API with OAuth, coexists peacefully with the disabled built-in module, and restores live rates plus protected managed tracking routes without touching core Magento code.
What AC-15210 actually is
Magento’s official bug tracker entry AC-15210 documents the breakage: Magento_Usps hardcodes requests to http://production.shippingapis.com/ShippingAPI.dll — the old USPS Web Tools XML endpoint. After January 25, 2026, that endpoint returns connection errors or empty responses depending on your server’s timeout configuration.
The symptoms in your store:
- Shipping method section shows no USPS options at checkout
- Magento error logs contain
USPS: Not Valid Countryor connection timeout errors - Order tracking links return 404 or empty pages
- 429 errors appearing in logs if you attempted the API migration USPS announced (the v3 endpoint requires OAuth, not USERID)
The underlying problem: Magento_Usps was never updated to support OAuth 2.0 client credentials or the v3 REST endpoints. It still references Zend_Http_Client patterns from Magento 1 heritage code. Backporting a patch would require replacing the HTTP client, the authentication layer, the request serializer, the response parser, and the tracking implementation — at that point you have rewritten the module. Skip the patch. Replace the carrier.
Why a clean replacement beats patching
The built-in module’s carrier class (Magento\Usps\Model\Carrier) inherits from AbstractCarrier but overrides so much of the rate collection and tracking logic that any partial patch creates a maintenance burden across every Magento security release. You would own a forked core module indefinitely.
The cleaner path: disable Magento_Usps entirely and install a new independent carrier module under your own namespace. Magento’s carrier system is designed for this — AbstractCarrier is the only interface contract. Third-party carriers like UPS, FedEx, and DHL all work this way. The RevAddress carrier follows the same pattern.
Benefits of the replacement approach:
- Zero modifications to Magento core or
vendor/ - Survives Magento security patches and version upgrades
- Clean namespace (
RevAddress_USPSv3) that won’t conflict with a future official fix - The old module stays registered (disabled, not removed), so historical order records that reference carrier code
uspscontinue to render correctly in the admin
The RevAddress USPS v3 carrier module
The RevAddress_USPSv3 Magento module wraps the RevAddress USPS v3 API. It handles OAuth token acquisition, rate requests against /prices/v3/total-rates/search, and tracking against /tracking/v3/tracking/{number}. Your Magento instance never touches the USPS OAuth endpoints directly — RevAddress holds the USPS OAuth credentials and your Magento store authenticates to RevAddress with a standard API key.
This matters for two reasons. First, USPS OAuth client credentials are tied to a single business application registration — you cannot embed them safely in a Magento config that is potentially shared across staging and production environments. Second, RevAddress handles the USPS rate limits (the v3 API enforces per-endpoint caps) and returns cached or degraded responses rather than surfacing raw 429s to your checkout flow.
Installation
Three steps. No Composer package yet — copy the module directly.
Step 1: Copy the module files
mkdir -p app/code/RevAddress/USPSv3
cp -r vendor/revaddress/magento-usps-v3/src/RevAddress/USPSv3/* app/code/RevAddress/USPSv3/ If you are pulling from the GitHub release directly:
cd /tmp
curl -sL https://github.com/revereveal/magento-usps-v3/archive/refs/tags/v1.0.0.tar.gz | tar xz
cp -r magento-usps-v3-1.0.0/src/RevAddress/USPSv3 /var/www/html/app/code/RevAddress/USPSv3 Step 2: Copy the shared HTTP client
mkdir -p app/code/RevAddress/Shared
cp -r vendor/revaddress/magento-usps-v3/src/RevAddress/Shared/* app/code/RevAddress/Shared/ Step 3: Enable, upgrade, and clean
bin/magento module:enable RevAddress_Shared RevAddress_USPSv3
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento cache:clean
bin/magento cache:flush Verify the module is active:
bin/magento module:status RevAddress_USPSv3
# Expected: Module is enabled Configuration
Navigate to Admin → Stores → Configuration → Sales → Shipping Methods. You will see a new USPS v3 (RevAddress) section.
| Field | Value |
|---|---|
| Enabled | Yes |
| Title | United States Postal Service |
| RevAddress API Key | Your rv_live_... key from /pricing |
| Origin ZIP Code | Your warehouse or fulfillment ZIP |
| Allowed Mail Classes | Priority Mail, Priority Mail Express, Ground Advantage, etc. |
| Show Method if Not Applicable | No |
| Debug | No (enable temporarily if rates are not appearing) |
For label generation, you will also see BYOK (Bring Your Own Keys) fields. If you have your own USPS business account, enter your USPS OAuth Client ID and Secret here. RevAddress will use your credentials directly for label requests. Leave these blank to use the RevAddress shared label pool.
After saving, clear the config cache:
bin/magento cache:clean config How rate collection works
The carrier implements Magento’s standard collectRates(RateRequest $request) contract. Here is the core flow:
<?php
// app/code/RevAddress/USPSv3/Model/Carrier.php
namespace RevAddress\USPSv3\Model;
use Magento\Shipping\Model\Carrier\AbstractCarrier;
use Magento\Shipping\Model\Carrier\CarrierInterface;
class Carrier extends AbstractCarrier implements CarrierInterface
{
protected string $_code = 'revaddress_usps';
public function collectRates(RateRequest $request): ?Result
{
if (!$this->getConfigFlag('active')) {
return null;
}
$payload = [
'originZIPCode' => $this->getConfigData('origin_zip'),
'destinationZIPCode' => $request->getDestPostcode(),
'weight' => $this->normalizeWeight($request),
'length' => $request->getPackageLength(),
'width' => $request->getPackageWidth(),
'height' => $request->getPackageHeight(),
'mailClasses' => $this->getAllowedMailClasses(),
];
$response = $this->client->post('/api/usps/rates', $payload);
$result = $this->rateResultFactory->create();
foreach ($response['rates'] as $rate) {
$method = $this->rateMethodFactory->create();
$method->setCarrier($this->_code);
$method->setCarrierTitle($this->getConfigData('title'));
$method->setMethod($rate['mailClass']);
$method->setMethodTitle($rate['description']);
$method->setPrice($rate['totalPrice'] / 100);
$method->setCost($rate['totalPrice'] / 100);
$result->append($method);
}
return $result;
}
} The client->post('/api/usps/rates') call hits the RevAddress API, which handles the USPS /prices/v3/total-rates/search integration. RevAddress normalizes the response, manages OAuth refresh, and enforces safe defaults if USPS returns a partial response (for example, when a mail class is unavailable for the requested dimensions).
Weight normalization converts Magento’s pound/ounce configuration into the gram values the v3 API expects.
Tracking integration
The carrier implements isTrackingAvailable() and getTracking(). Tracking requests route through RevAddress to the USPS /tracking/v3/tracking/{number} endpoint.
<?php
public function isTrackingAvailable(): bool
{
return true;
}
public function getTracking(string|array $trackings): Result
{
$result = $this->trackFactory->create();
foreach ((array) $trackings as $number) {
$response = $this->client->get("/api/usps/tracking/{$number}");
$status = $this->trackStatusFactory->create();
$status->setCarrier($this->_code);
$status->setCarrierTitle($this->getConfigData('title'));
$status->setTracking($number);
$status->setTrackSummary($response['summary'] ?? '');
if (!empty($response['events'])) {
$status->setProgressdetail($this->formatEvents($response['events']));
}
$result->append($status);
}
return $result;
} Tracking results appear in the standard Magento My Orders → Track Order flow with no template changes required. The carrier code revaddress_usps is what Magento stores on new orders created after the module is enabled.
Disabling the old Magento_Usps module
Disable — do not remove. Removing the module deletes the database schema entries that historical orders reference when rendering the carrier name in admin.
bin/magento module:disable Magento_Usps
bin/magento setup:upgrade
bin/magento cache:clean Before running this, check whether you have orders that used the old usps carrier code:
mysql -u magento -p magento -e \
"SELECT COUNT(*) as order_count FROM sales_order WHERE shipping_method LIKE 'usps_%';" If that count is above zero, keep the module disabled (not removed). Magento will still render the carrier name for historical orders — it reads from sales_order.shipping_description which is a stored string, not a live carrier lookup. The module code itself is no longer called. You get clean separation: old orders display correctly, new orders go through revaddress_usps.
If the count is zero (fresh store or all orders shipped before USPS broke), you can remove the module entirely from vendor/ after disabling, but disabled is sufficient and safer.
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| No rates at checkout | API key not saved or wrong environment | Verify key in config, clear cache, enable Debug mode, check var/log/shipping.log |
| Rates appear but are $0.00 | Weight not set on products | Set product weight in grams or check unit config under carrier settings |
| 429 errors in logs | RevAddress rate limit exceeded (unlikely on standard plans) | Check your plan limits at /pricing; contact support if unexpected |
| Tracking shows “No information” | Order created with old usps carrier code or USPS has not recognized the new item yet | Old orders route to Magento_Usps — not fixable retroactively; new orders hit the v3 tracking route once USPS recognizes the parcel |
| Config not saving | Magento config cache | Run bin/magento cache:clean config after every save |
| Module not found after enable | DI compile not run | Run bin/magento setup:di:compile |
| Carrier not appearing in admin | Wrong section — check Sales > Shipping Methods, not Carriers | Navigate to Stores → Configuration → Sales → Shipping Methods |
What you have after this fix
- Live USPS rates at checkout via the v3 REST API
- Priority Mail, Priority Mail Express, Ground Advantage, and all v3 mail classes
- Protected tracking integration against the v3 tracking endpoint; event detail appears as USPS scan data becomes available
- Label generation (with either RevAddress shared pool or your own USPS OAuth credentials via BYOK)
- No modifications to Magento core — survives upgrades cleanly
- Historical orders using the old
uspscarrier code continue to display correctly
The AC-15210 bug is a known upstream issue with no official Magento patch timeline. The replacement carrier approach is the most dependable path that Magento enterprise agencies have been deploying since February 2026.
Get started: Create a free RevAddress account — the free proof path lets you test rate requests and address validation first, then expand into protected managed tracking routes before you expose customer-facing shipment status.
Related reading:
- USPS Web Tools Migration Checklist — every step, in order
- USPS Web Tools shutdown: what it means for your stack
- USPS OAuth troubleshooting: the complete guide
- Shipping API Comparison 2026 — EasyPost vs Shippo vs ShipEngine vs RevAddress
- Full API reference and integration docs
Keep the free proof wedge first
USPS v3 developer toolkit. Free tier for validation and rates. Flat monthly pricing.
Validation, ZIP+4, and rates are the free proof path. Labels, tracking, BYOK, and pickup stay protected until the workflow and proof gates are actually ready.