Magento 2 USPS shipping method integration migration from SOAP to RESTful API

By | October 7, 2025
Spread the love

That’s an excellent initiative — migrating Magento 2 USPS integration from SOAP to REST is both forward-looking and increasingly necessary, since USPS has deprecated many SOAP-based endpoints and newer APIs (Shipping API v2, Label API, etc.) are REST-first.

Let’s break this into a complete migration guide, covering what you need to replace, reimplement, and test.


Overview

Current (SOAP-based)

Magento 2’s core USPS carrier module (Magento\Usps\Model\Carrier) historically used:

  • USPS RateV4, IntlRateV2, etc. via XML-over-HTTP (SOAP-like).

  • Requests built manually using XML payloads, sent with \Magento\Framework\HTTP\ZendClient.

New (REST-based)

USPS now offers:

  • USPS Web Tools REST API (2024+ version) for:

    • Rate Quotes (/rates/v1/rate)

    • Labels (/labels/v1/label)

    • Tracking (/tracking/v1/tracking)

  • Auth via OAuth 2.0 client credentials instead of static USERID.

  • JSON payloads instead of XML.


🧩 Step-by-Step Migration Plan

1. Get USPS Web Tools REST Credentials

  1. Log in to USPS Web Tools Developer Portal.

  2. Create an app and obtain:

    • Client ID

    • Client Secret

  3. Enable relevant APIs (Rates, Labels, Tracking).


2. Extend or Replace the Existing USPS Carrier Module

You can either:

  • Extend Magento\Usps\Model\Carrier (recommended for compatibility)

  • ❌ Or replace it entirely with a custom carrier (for clean REST-only logic)

Create your custom carrier class, e.g.:

app/code/Vendor/UspsRest/Model/Carrier/Usps.php

In etc/config.xml:

<default>
    <carriers>
        <usps_rest>
            <active>1</active>
            <model>Vendor\UspsRest\Model\Carrier\Usps</model>
            <title>USPS (REST)</title>
            <name>USPS</name>
        </usps_rest>
    </carriers>
</default>

 

3. Implement REST Request Logic

Old SOAP (simplified):

$client = new \Zend_Http_Client($url);
$client->setParameterPost(['API' => 'RateV4', 'XML' => $xmlPayload]);
$response = $client->request('POST');

New REST (JSON):

use Magento\Framework\HTTP\Client\Curl;

$authUrl = 'https://api.usps.com/oauth2/v1/token';
$rateUrl = 'https://api.usps.com/rates/v1/rate';

$curl = new Curl();
$curl->addHeader('Content-Type', 'application/json');
$curl->addHeader('Authorization', 'Bearer ' . $accessToken);

$payload = [
    'rateOptions' => [
        'carrier' => 'usps',
        'serviceType' => 'PRIORITY',
        'packageWeight' => '2',
        'originZIPCode' => '94105',
        'destinationZIPCode' => '10001',
    ],
];

$curl->post($rateUrl, json_encode($payload));
$response = json_decode($curl->getBody(), true);

 


4. OAuth2 Token Handling

Implement a helper to handle token caching and refreshing:

namespace Vendor\UspsRest\Helper;

use Magento\Framework\App\Helper\AbstractHelper;
use Magento\Framework\App\CacheInterface;

class Auth extends AbstractHelper
{
    protected $cache;
    protected $curl;

    public function __construct(CacheInterface $cache, \Magento\Framework\HTTP\Client\Curl $curl)
    {
        $this->cache = $cache;
        $this->curl  = $curl;
    }

    public function getAccessToken()
    {
        $token = $this->cache->load('usps_rest_token');
        if ($token) return $token;

        $this->curl->post('https://api.usps.com/oauth2/v1/token', [
            'grant_type' => 'client_credentials',
            'client_id' => 'YOUR_CLIENT_ID',
            'client_secret' => 'YOUR_CLIENT_SECRET'
        ]);

        $data = json_decode($this->curl->getBody(), true);
        $token = $data['access_token'] ?? null;

        if ($token) $this->cache->save($token, 'usps_rest_token', [], 3500);
        return $token;
    }
}

 

5. Rate Collection

Override collectRates() in your new carrier model:

public function collectRates(\Magento\Quote\Model\Quote\Address\RateRequest $request)
{
    if (!$this->getConfigFlag('active')) {
        return false;
    }

    $result = $this->_rateResultFactory->create();
    $accessToken = $this->authHelper->getAccessToken();

    $response = $this->rateService->getRates($request, $accessToken);

    foreach ($response['rates'] as $rate) {
        $method = $this->_rateMethodFactory->create();
        $method->setCarrier('usps_rest');
        $method->setCarrierTitle($this->getConfigData('title'));
        $method->setMethod($rate['serviceType']);
        $method->setMethodTitle($rate['serviceType']);
        $method->setPrice($rate['totalRate']);
        $method->setCost($rate['totalRate']);
        $result->append($method);
    }

    return $result;
}

6. Testing & Validation

  1. Use USPS sandbox API endpoints first.

  2. Enable debug logging:

    <default>
        <carriers>
            <usps_rest>
                <debug>1</debug>
            </usps_rest>
        </carriers>
    </default>
    
  3. Validate:

    • Domestic and international rates

    • Handling of multiple packages

    • Label printing (if implemented)

    • Tracking numbers


7. Backward Compatibility

If you want to keep the old USPS SOAP active:

  • Add a toggle in Admin Configuration (carriers/usps_rest/enable_rest_api)

  • Allow switching between old XML and new REST logic dynamically.


⚙️ USPS REST API References

APIEndpointDescription
OAuth2/oauth2/v1/tokenObtain access token
Rate Quotes/rates/v1/rateGet shipping rates
Labels/labels/v1/labelCreate shipping labels
Tracking/tracking/v1/trackingTrack shipments

Full docs:
🔗 https://developer.usps.com/apis


🧠 Migration Tips

  • Don’t reuse old XML payload logic — REST uses JSON and new field names.

  • Handle USPS service names carefully — they differ (e.g., “PriorityMail” → “PRIORITY”).

  • Cache tokens and rates to improve performance.

  • Use try/catch around Curl requests — USPS REST APIs sometimes return 502/504 intermittently.

Buy plugin by below link

https://www.ecomplugins.com/magento2-usps-shipping-with-rest-api