Skip to content
All Posts
Migration Guide

WooCommerce USPS Migration: From Web Tools to v3 REST API

· 8 min read · By RevAddress · Migration Guide

If your WooCommerce store stopped showing USPS shipping rates at checkout, you are not alone — and you did not break anything. USPS broke it for everyone on January 25, 2026 when they shut down the Web Tools XML API. Every plugin built on that API stopped working the same day.

This guide covers exactly what happened, what the new API requires, and how to get live USPS rates back at checkout using the RevAddress WooCommerce module.

Why Your WooCommerce USPS Plugin Broke

USPS retired the Web Tools XML API (ShippingAPI.dll) on January 25, 2026. The shutdown was announced in 2024 and affected every plugin that made calls to secure.shippingapis.com or production.shippingapis.com.

Plugins confirmed dead as of that date:

  • WooCommerce USPS Shipping Method (WooCommerce.com official extension) — called ShippingAPI.dll?API=RateV4
  • Stamps.com for WooCommerce — used Web Tools for rate lookups via the Stamps.com wrapper
  • WP Overnight USPS — direct Web Tools XML
  • ShipStation Connect — partial dependency on Web Tools for rate quoting
  • Any custom plugin or snippet that hits shippingapis.com with a USERID parameter

The error you got — no rates at checkout, empty rate list, or a PHP cURL error 6: Could not resolve host — is the XML API returning nothing because the endpoint no longer exists.

What Changed: XML to REST

The new USPS v3 API is a complete architectural break from Web Tools. It is not a version bump.

What changedWeb Tools (dead)USPS v3 REST (current)
ProtocolXML over HTTPSJSON REST
AuthUSERID query parameterOAuth 2.0 bearer token
Rate lookupBatch XML requestPer-call JSON endpoint
Address fieldsAddress1 (secondary), Address2 (street)streetAddress (street), secondaryAddress (apt)
Endpointsecure.shippingapis.com/ShippingAPI.dllapi.usps.com/prices/v3/...
RegistrationUSPS Web Tools portal (closed)developers.usps.com

The Address1/Address2 field swap is the most common source of bugs when people try to hand-roll their own v3 integration. The old API used Address2 for the street address and Address1 for the apartment or suite. The new API uses streetAddress and secondaryAddress in the correct semantic order.

For a deeper look at the OAuth flow, see USPS OAuth Troubleshooting.

The RevAddress WooCommerce Module

The RevAddress USPS v3 module is a drop-in WooCommerce shipping method that replaces the dead XML plugins. It uses the RevAddress developer toolkit for USPS v3 integration, which means:

  • OAuth token refresh is handled server-side — your store never manages USPS credentials directly
  • Live rates at checkout for Priority Mail, Priority Express, Ground Advantage, First-Class, and Media Mail
  • Address validation with DPV (Delivery Point Validation) at checkout — catches bad addresses before orders ship
  • Fallback flat rates when USPS is unavailable, so checkout never breaks
  • Rate caching (60 seconds) to stay inside USPS rate limits without slowing down checkout

The module is a single PHP file plus an assets directory — no Composer, no Guzzle, no dependency tree. It works on any WooCommerce installation that can make outbound HTTPS calls.

Installing the WooCommerce USPS v3 Module

Step 1: Upload the plugin files

Download the module from revaddress.com/docs/woocommerce and upload the directory to your WordPress plugins folder.

Plugin directory structure
wp-content/plugins/
revaddress-usps-shipping/
  revaddress-usps-shipping.php   # Plugin entry point + shipping method class
  includes/
    class-rate-fetcher.php       # USPS v3 rate API calls
    class-address-validator.php  # DPV address validation
    class-token-cache.php        # OAuth token management (WP transients)
  assets/
    admin.js                     # Settings page enhancements
    checkout.js                  # Address validation UI feedback
  readme.txt

Step 2: Activate the plugin

Go to Plugins → Installed Plugins in your WordPress admin, find “RevAddress USPS Shipping”, and click Activate.

Step 3: Configure the shipping method

Go to WooCommerce → Settings → Shipping, click your shipping zone, then Add shipping method → RevAddress USPS v3.


Configuration Walkthrough

The settings screen has five sections. Here is what each one does.

RevAddress API Key — Your rv_live_ key from revaddress.com/signup. This is what authenticates your store to the RevAddress API. Get one free at revaddress.com/signup.

Origin ZIP Code — The 5-digit ZIP where your orders ship from. This is required for accurate rate calculation. USPS v3 calculates rates based on origin-to-destination distance.

Mail Classes — Checkboxes for which USPS services to offer at checkout. Options: Priority Mail, Priority Mail Express, Ground Advantage, First-Class Package (under 1 lb), Media Mail (books/educational media only). Enable only what your store actually ships.

Address Validation — When enabled, RevAddress validates the shipping address against the USPS DPV database before the customer can complete checkout. DPVConfirmation: D (missing apartment number) shows a warning. DPVConfirmation: N (not a deliverable address) blocks submission. This eliminates a significant share of undeliverable packages.

Fallback Rate — A flat rate shown when the USPS API returns no rates (rate limit, timeout, or package outside USPS constraints). Set this to something reasonable like $9.99 so checkout never shows zero shipping options.


How the Module Fetches Rates

The rate fetch happens inside calculate_shipping() — the WooCommerce hook that runs when a customer enters a shipping address or updates the cart.

Rate fetch — class-rate-fetcher.php
class RevAddress_Rate_Fetcher {

  private string $api_key;
  private string $origin_zip;

  public function __construct( string $api_key, string $origin_zip ) {
      $this->api_key    = $api_key;
      $this->origin_zip = $origin_zip;
  }

  public function get_rates( array $package ): array {
      $destination = $package['destination'];
      $weight_oz   = $this->cart_weight_to_ounces( $package );

      $body = wp_json_encode( [
          'originZIPCode'      => $this->origin_zip,
          'destinationZIPCode' => $destination['postcode'],
          'weight'             => $weight_oz,
          'length'             => 12,
          'width'              => 9,
          'height'             => 3,
          'mailClasses'        => [ 'PRIORITY_MAIL', 'GROUND_ADVANTAGE', 'FIRST_CLASS_PACKAGE_SERVICE' ],
      ] );

      $response = wp_remote_post(
          'https://api.revaddress.com/api/rates/calculate',
          [
              'headers' => [
                  'X-API-Key'    => $this->api_key,
                  'Content-Type' => 'application/json',
              ],
              'body'    => $body,
              'timeout' => 8,
          ]
      );

      if ( is_wp_error( $response ) ) {
          return [];
      }

      $data = json_decode( wp_remote_retrieve_body( $response ), true );

      return $data['rates'] ?? [];
  }

  private function cart_weight_to_ounces( array $package ): float {
      // WooCommerce weight unit is configurable — convert to ounces for USPS
      $weight    = WC()->cart->get_cart_contents_weight();
      $wc_unit   = get_option( 'woocommerce_weight_unit' );

      switch ( $wc_unit ) {
          case 'lbs': return round( $weight * 16, 2 );
          case 'kg':  return round( $weight * 35.274, 2 );
          case 'g':   return round( $weight * 0.035274, 2 );
          default:    return round( $weight, 2 ); // already oz
      }
  }
}

The weight conversion is the part that breaks most hand-rolled integrations. WooCommerce stores weight in whatever unit the store owner configured — pounds, kilograms, grams, or ounces. USPS v3 only accepts ounces. The switch handles all four WooCommerce weight units.

How address validation hooks into checkout

Address validation runs on two hooks: woocommerce_after_checkout_validation (server-side, before order is created) and an optional AJAX endpoint for real-time field feedback.

Checkout validation hook — revaddress-usps-shipping.php
add_action( 'woocommerce_after_checkout_validation', [ $this, 'validate_shipping_address' ], 10, 2 );

public function validate_shipping_address( array $data, WP_Error $errors ): void {
  if ( ! $this->address_validation_enabled() ) {
      return;
  }

  $validator = new RevAddress_Address_Validator( $this->get_option( 'api_key' ) );
  $result    = $validator->validate( [
      'streetAddress'    => $data['shipping_address_1'],
      'secondaryAddress' => $data['shipping_address_2'],
      'city'             => $data['shipping_city'],
      'state'            => $data['shipping_state'],
      'ZIPCode'          => $data['shipping_postcode'],
  ] );

  if ( ! $result['valid'] ) {
      $errors->add(
          'invalid_shipping_address',
          sprintf(
              __( 'Shipping address could not be verified: %s. Please check your address and try again.', 'revaddress-usps' ),
              esc_html( $result['reason'] )
          )
      );
  }
}

When DPVConfirmation comes back as N, the validator sets valid: false with reason: "Address not found in USPS database". The checkout error prevents the order from being created with a bad address. This is the same DPV check that postal carriers use.

Rate caching

USPS v3 rate limits are 60 calls per hour per OAuth client at the free tier. With address validation calls, a busy store can hit that ceiling fast. The module caches rates in WP transients for 60 seconds, keyed on origin ZIP + destination ZIP + weight bucket.

Transient cache in calculate_shipping()
public function calculate_shipping( $package = [] ): void {
  $cache_key = 'revaddress_rates_' . md5(
      $this->origin_zip .
      $package['destination']['postcode'] .
      (string) round( WC()->cart->get_cart_contents_weight(), 1 )
  );

  $cached = get_transient( $cache_key );

  if ( false !== $cached ) {
      foreach ( $cached as $rate ) {
          $this->add_rate( $rate );
      }
      return;
  }

  $fetcher = new RevAddress_Rate_Fetcher( $this->get_option( 'api_key' ), $this->origin_zip );
  $rates   = $fetcher->get_rates( $package );

  if ( empty( $rates ) ) {
      $fallback = (float) $this->get_option( 'fallback_rate', '0' );
      if ( $fallback > 0 ) {
          $this->add_rate( [
              'id'    => 'revaddress_fallback',
              'label' => __( 'Standard Shipping', 'revaddress-usps' ),
              'cost'  => $fallback,
          ] );
      }
      return;
  }

  set_transient( $cache_key, $rates, 60 );

  foreach ( $rates as $rate ) {
      $this->add_rate( $rate );
  }
}

Common Issues and Fixes

SymptomCauseFix
No rates appear at checkoutAPI key not configured or invalidVerify you are using a live key — sandbox evaluation keys do not return production rates
”Rate limit exceeded” in logs60 req/hr USPS ceiling hitEnable transient caching in settings, or upgrade to a RevAddress plan with higher limits
Address validation blocks valid addressesDPV strict mode on secondary addressSet validation mode to “warn” instead of “block” in settings, or disable for P.O. box–heavy markets
USPS credentials not configured errorUsing an old API key or wrong environmentDelete old key, generate a new one at revaddress.com/dashboard
Rates show in sandbox but not productionSandbox mode still enabledSettings → uncheck “Sandbox mode”
Weight always shows as 0 ozWooCommerce products have no weight setAdd weight to each product in WooCommerce → Products → Edit → Shipping tab
PHP fatal on activationWooCommerce not activeRevAddress USPS requires WooCommerce 7.0+ to be installed and active

For OAuth-specific errors (401, invalid_client, token expired), see USPS OAuth Troubleshooting. The OAuth layer is managed by the RevAddress API so most stores never see token errors, but that post covers what the error codes mean if you are debugging logs.


For Stores That Also Create Shipping Labels

Fetching rates at checkout and printing labels are two separate USPS v3 permissions. Most stores only need rates and address validation — that is the default module configuration and it works on a standard RevAddress API key.

If your store also creates USPS shipping labels directly (instead of using a third-party like ShipStation or Pirateship), you need additional USPS credentials and an extra configuration section called BYOK (Bring Your Own Keys).

BYOK label credentials — settings screen
// These fields appear in Settings > RevAddress USPS > Label Configuration
// Only required for direct label creation — not needed for rates or address validation

'crid'       => 'Customer Registration ID — from USPS Business Customer Gateway',
'master_mid' => 'Master Mailer ID — your USPS account MID',
'label_mid'  => 'Label Mailer ID — can match Master MID for single-location stores',
'epa'        => 'Electronic Payment Account number — required for postage billing'

CRID and MID values come from your USPS Business Customer Gateway account at gateway.usps.com. USPS assigns these during the eVS or Shipping Services enrollment process. If you do not have them, you do not yet have label-creation permissions.

One additional requirement for label creation: COP (Customer Order Processing) claims linking. This connects your USPS payment account to your API credentials. It is a manual USPS process that currently cannot be done through the API — you need to call USPS Business Customer Support and reference your MID. This is documented in the RevAddress BYOK docs.

Until COP linking is complete, address validation and rate lookups work fine — only label creation is blocked.


Getting Your API Key

The module requires a RevAddress API key. It is free to start:

  1. Go to revaddress.com/pricing and pick a plan — the Starter plan covers address validation and rate lookups for small stores
  2. Complete checkout
  3. Your API key (rv_live_...) is on the dashboard immediately
  4. Paste it into WooCommerce → Settings → Shipping → RevAddress USPS v3 → API Key

If you are evaluating before purchasing, free API keys are available and are meant for safe integration proof before purchase. Switch to a live key when you are ready for production carrier traffic.

For the full API reference including all rate endpoints, address validation parameters, and batch operations, see the RevAddress API docs.


The Web Tools API is not coming back. Every week you run a dead plugin is a week your store either shows no shipping options or is running a broken checkout flow. The RevAddress module is a one-afternoon migration — upload, activate, configure your API key and origin ZIP, and you have live USPS rates back.

Questions not covered here: the RevAddress docs have the full module reference, or open a support ticket from your dashboard.

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.