Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
8affae7
Issue #510: Code changes to support USPS’s OAuth2 API integration.
bugfolder Apr 20, 2025
40ec8fa
Add insurance and signature confirmation settings.
bugfolder Jun 8, 2025
1978376
Update return value in shipping/uc_usps/uc_usps.module
bugfolder Jun 24, 2025
c537554
Update return value in shipping/uc_usps/uc_usps.module
bugfolder Jun 24, 2025
39d1574
Update return value in docblock in shipping/uc_usps/uc_usps.module
bugfolder Jun 24, 2025
4ca3bb0
Update return value in docblock in shipping/uc_usps/uc_usps.module
bugfolder Jun 24, 2025
0ad2571
Update return value in docblock in shipping/uc_usps/uc_usps.module
bugfolder Jun 24, 2025
58e30b7
Update return value in docblock in shipping/uc_usps/uc_usps.module
bugfolder Jun 24, 2025
32e3366
Update return value in docblock in shipping/uc_usps/uc_usps.module
bugfolder Jun 24, 2025
27a6e3e
Update return value in docblock in shipping/uc_usps/uc_usps.module
bugfolder Jun 24, 2025
ad05eeb
Update return value in docblock and fix typo in shipping/uc_usps/uc_u…
bugfolder Jun 24, 2025
76742d7
Update return value in docblock in shipping/uc_usps/uc_usps.module
bugfolder Jun 24, 2025
baf9f80
Update return value in docblock in shipping/uc_usps/uc_usps.module
bugfolder Jun 24, 2025
a3d714f
Updates in respons to PR review.
bugfolder Jun 25, 2025
6b00be5
Merge branch '1.x-3.x' into 510_usps_oauth
bugfolder Aug 26, 2025
44f401b
Merge branch '1.x-3.x' into 510_usps_oauth
bugfolder Aug 26, 2025
8ada436
Change names of client ID and client secret to Consumer Key and Consu…
bugfolder Aug 30, 2025
97f83ef
Update shipping/uc_usps/config/uc_usps.settings.json
bugfolder Sep 24, 2025
4f13ba2
Update shipping/uc_usps/config/uc_usps.settings.json
bugfolder Sep 24, 2025
3c8bd0f
Update shipping/uc_usps/uc_usps.module
bugfolder Sep 24, 2025
e81892c
Update shipping/uc_usps/uc_usps.module
bugfolder Sep 24, 2025
88dc6a8
Improve error handling in new API functions.
bugfolder Sep 25, 2025
0235124
Add package size computation for all-in-one packaging.
bugfolder Sep 25, 2025
3f4b24d
Update shipping/uc_usps/config/uc_usps.settings.json
bugfolder Sep 25, 2025
81292be
Update shipping/uc_usps/config/uc_usps.settings.json
bugfolder Sep 25, 2025
c38d57d
Pretty-print debug data; fix rate info filtering for all-in-one.
bugfolder Sep 26, 2025
e4b509c
Improve support for non-standard packages.
bugfolder Nov 18, 2025
2ee0529
Small edits to the UPGRADING documentation.
bugfolder Nov 18, 2025
b313c82
Remove stray dpm().
bugfolder Nov 18, 2025
07360ed
Merge branch '1.x-3.x' into 510_usps_oauth
bugfolder Nov 18, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 104 additions & 0 deletions shipping/uc_usps/UPGRADING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Upgrading to the new USPS API

## Overview

For many years, the Drupal 7 and Backdrop versions of Ubercart have used the USPS Web Tools API for postal rate lookups. [That API is now being deprecated by USPS](https://www.usps.com/business/web-tools-apis/welcome.htm) in favor of their [new OAuth2-based API](https://developers.usps.com). This new API makes many changes that will affect Ubercart stores that use the `uc_usps` module to do rate lookups:

* There are options that are no longer available (like "online prices");
* There are new options that are available (like a distinction between Retail, Commercial, and Contract rates).

To support Ubercart stores that use the `uc_usps` module, this module now supports both the **Legacy** API (the old Web Tools API) and the **new API**. New installations can choose which API to use. However:

* **The old Web Tools API will be turned off by USPS on January 25, 2026.**

All Ubercart stores should switch to the new API before then. Future releases of Backdrop CMS Ubercart will only support the new USPS API going forward.

## Background: the Legacy API

The Ubercart USPS module `uc_usps` recognizes two options for the **Default product shipping type**: _Envelope_ and _Small package_. Shipping type _Small package_ is a default shipping type defined by the `uc_quote` module. Module `uc_usps` adds the additional shipping type of _Envelope_.

You can then further set a package type for the product (labeled **Package type** on the product edit form); this select element has many options, such as _Variable_, _Flat rate envelope_, and more. However, only _Small package_ lets you set the package type to anything other than _Variable_.

That means that any _Envelope_ products can still be offered to be shipped in a box. You can't actually specify that it can _only_ be shipped in some type of envelope. However, this is useful, because if you have selected the _All in one_ option in the quote options for USPS, it will permit both _Envelope_ and _Small package_ products to be shipped in the same box.

Another interesting feature of the existing USPS module is that while it offers the user a choice of several different rates, it will ship all packages via the same rate, even if it would be cheaper to ship, say, one product in an envelope and another in a box.

(Note that there was a bug in the rendering of of the services presented to the user to choose from, which did not correctly list the number of packages being shipped. This has been fixed in the current version.)

When you upgrade Ubercart to this version, your settings will be left using the legacy API. You will need to manually switch to the new API at a time that is convenient for you. You can switch back and forth between the two APIs in order to see the effects of changes.

To upgrade to the new API for rate lookups, you will need to select the new API in the settings for USPS shipping and then choose various configuration options, some of which are similar to the legacy API options and some of which are new. We strongly recommend doing this at a time where there are no carts in checkout or other pending statuses, as the results of a new lookup versus an old lookup may well be different in price, type of mail, et cetera. We suggest taking the store offline, then changing the configuration settings, and, if possible, carrying out several test orders to verify that all lookups are working well before bringing the store back online.

## Setting up OAuth2 Credentials with USPS

The new USPS API uses OAuth2 validation, which you will need to set up on the [USPS Developer Portal](https://developers.usps.com). In the old API, you had a USPS User ID, which never changed and was all that was needed to do a rate lookup. With the OAuth2 API, every lookup contains an OAUth2 access token, which is time-limited and expires after several hours. The USPS module takes care of obtaining the necessary token and renewing it regularly; this is done transparently, so you don't need to worry about it. However, in order to obtain the token, you will need to obtain a Client ID and a Client Secret (which are both long strings, the latter longer than the former), and enter these into the settings.

You will do that by creating an account on the USPS site (click "Sign up" on the Developer Portal), but you may already have an account (you needed one to create the original User ID for the Web Tools API).

Once you are signed in, go to developers.usps.com, and you will see Apps in the top menu bar. Click on that—you will need to create an "App" for API access. Click on the "Add App" button, which will open up a form:

* App name — give your App a name (which could be the name of your store).
* Callback URL — This is not used by `uc_usps`, so you can leave it blank.
* Description — make this whatever you want.
* APIs — Check the "Public Access I" box (the only one). This is what will give you access to the rate lookup endpoints (and several others not used by `uc_usps`, though they might be added in the future).

Then click "Add App." This will create the new App.

When the App is created, you will see some details about it. Two are very important:

* Consumer Key — this is the "Client ID" that you will need to enter into Ubercart settings.
* Consumer Secret — this is the "Client Secret" that you will need to enter into Ubercart settings.

Both of these are required for Ubercart to obtain an access token in order to do rate lookups. Copy them both, and keep them in a safe place (ideally, an encrypted safe place).

### Configure Ubercart USPS

Now you are ready to configure the USPS shipping settings.

## Configuration

The configuration options can be found at Admin > Store > Configuration > Shipping quotes > Settings > USPS, i.e., at path admin/store/settings/quotes/settings/usps. Click through each of the vertical tab sets as described below, then click "Save Configuration" to switch to the new API. Your legacy API settings will remain saved, so you can easily switch back and forth.

### Credentials

The first setting in the Credentials tab is **Method**: select _New API_ to switch to the new API. When you do this, the fields below **Method* will change. (New installations of Ubercart will automatically be set to use the new API.)

#### USPS client ID

Enter the "Consumer Key" from your USPS account.

#### USPS client secret

Enter the "Consumer Secret" from your USPS account. This will be saved but not displayed when you save the configuration; you shouldn't need to enter it again.

#### Connection address

Select either "Testing" or "Production". Use the former while you are testing out the system, the latter once you are processing real transactions.

Once you have entered those values, click "Save Configuration." You should see a success message posted to the top of the stage and the **Access token** field will be populated. This token expires after 8 hours but will be automatically updated as needed.

### USPS domestic

This tab lists all of the services for _Envelope_ and _Small package_ products. These are generally different from the services offered by the legacy API, although there is a rough correspondence. For example, "First Class Mail Stamped Letter" in the legacy API is "First Class Letter Metered" in the new API. Select the services that you wish to offer for each type of package; you should find rough equivalents to the legacy API settings in the new services lists.

### USPS international

The same goes for international services.

### Quote options

#### Product packages

As in the legacy API, you can choose whether each product should be shipped in its own package or all products shipped in a single package. Note that with multiple packages, all packages will be shipped via the same service, so you should not choose service options for _Envelope_ and _Small package_ that are incompatible if there is a possibility of both products being shipped together.

#### Price type

This is a new setting, which replaced the previous "Use online rates" checkbox. You can select Retail, Commercial, or Contract rates to quote. (Retail rates are often a bit higher than Commercial rates.)

#### Markups

Markups are the same as they were in the legacy API: you can mark up products by a percentage of their price and/or mark up the weight sent to the rate lookup to account for the weight of shipping materials, etc.

When you are done, click "Save Configuration." You're done! You and your customers can now continue to put items in the cart and checkout as usual. During checkout, customers will be presented with a choice of all qualifying services and their rates, so do make sure that you have only allowed those services that you are prepared to provide.


134 changes: 132 additions & 2 deletions shipping/uc_usps/config/uc_usps.settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,135 @@
"uc_usps_weight_markup_type": "percentage",
"uc_usps_weight_markup": 0,
"uc_usps_markup": "",
"uc_usps_markup_type": ""
}
"uc_usps_markup_type": "",
"uc_usps_authorization_method": "newapi",
"uc_usps_token_expiry": "0",
"uc_usps_client_id": "",
"uc_usps_client_secret": "",
"uc_usps_access_token": "",
"uc_usps_token_expiry": 1748412318,
"uc_usps_connection_address": "https://apis-tem.usps.com",
"uc_usps_price_type": "COMMERCIAL",
"uc_usps_newapi_dom_env_all_services": {
"FCLM": "First Class Letter Metered",
"FCP": "First Class Postcards",
"FCF": "First Class Flats",
"PMFRE": "Priority Mail Flat Rate Envelope",
"PMPFRE": "Priority Mail Padded Flat Rate Envelope",
"PMLFRE": "Priority Mail Legal Flat Rate Envelope",
"PMMS": "Priority Mail Machinable Single-piece",
"PMEFRE": "Priority Mail Express Flat Rate Envelope",
"PMEPFRE": "Priority Mail Express Padded Flat Rate Envelope",
"PMELFRE": "Priority Mail Express Legal Flat Rate Envelope",
"PMELFREHD": "Priority Mail Express Legal Flat Rate Envelope Holiday Delivery",
"PMEMS": "Priority Mail Express Machinable Single-piece",
"UGAMS": "USPS Ground Advantage Machinable Single-piece"
},
"uc_usps_newapi_dom_parcel_all_services": {
"FCLM": "First Class Letter Metered",
"FCF": "First Class Flats",
"PMMSFRB": "Priority Mail Machinable Small Flat Rate Box",
"PMMMFRB": "Priority Mail Machinable Medium Flat Rate Box",
"PMMLFRB": "Priority Mail Machinable Large Flat Rate Box",
"PMMLFRBA": "Priority Mail Machinable Large Flat Rate Box APO/FPO/DPO",
"PMMS": "Priority Mail Machinable Single-piece",
"PMMCNPT1": "Priority Mail Machinable Cubic Non-Soft Pack Tier 1",
"PMMCSPT1": "Priority Mail Machinable Cubic Soft Pack Tier 1",
"PMEMS": "Priority Mail Express Machinable Single-piece",
"UGAMS": "USPS Ground Advantage Machinable Single-piece",
"UGAMCNPT1": "USPS Ground Advantage Machinable Cubic Non-Soft Pack Tier 1",
"UGAMCSPT1": "USPS Ground Advantage Machinable Cubic Soft Pack Tier 1",
"BPMMP": "Bound Printed Matter Machinable Presorted",
"BPMNP": "Bound Printed Matter Nonstandard Presorted",
"LMNB": "Library Mail Nonstandard Basic",
"LMM5": "Library Mail Machinable 5-digit",
"LMN5": "Library Mail Nonstandard 5-digit",
"MMNB": "Media Mail Nonstandard Basic",
"MMM5": "Media Mail Machinable 5-digit",
"MMN5": "Media Mail Nonstandard 5-digit"
},
"uc_usps_newapi_intl_env_all_services": {
"FCLM": "First Class Letter Metered",
"FCP": "First Class Postcards",
"FCF": "First Class Flats",
"FPISMIS": "First-Class Package International Service Machinable ISC Single-piece",
"PMIIFRE": "Priority Mail International ISC Flat Rate Envelope",
"PMIMIPFRE": "Priority Mail International Machinable ISC Padded Flat Rate Envelope",
"PMIIS": "Priority Mail International ISC Single-piece",
"PMIMIS": "Priority Mail International Machinable ISC Single-piece",
"PMIILFRE": "Priority Mail International ISC Legal Flat Rate Envelope",
"PMEIIFRE": "Priority Mail Express International ISC Flat Rate Envelope",
"PMEIILFRE": "Priority Mail Express International ISC Legal Flat Rate Envelope",
"PMEIIS": "Priority Mail Express International ISC Single-piece",
"PMEIIPFRE": "Priority Mail Express International ISC Padded Flat Rate Envelope"
},
"uc_usps_newapi_intl_parcel_all_services": {
"FPISMIS": "First-Class Package International Service Machinable ISC Single-piece",
"PMIMILFRB": "Priority Mail International Machinable ISC Large Flat Rate Box",
"PMIMIMFRB": "Priority Mail International Machinable ISC Medium Flat Rate Box",
"PMIIS": "Priority Mail International ISC Single-piece",
"PMIMIS": "Priority Mail International Machinable ISC Single-piece",
"PMEIIS": "Priority Mail Express International ISC Single-piece"
},
"uc_usps_newapi_dom_env_services": {
"FCLM": "FCLM",
"FCP": "FCP",
"FCF": "FCF",
"PMFRE": "PMFRE",
"PMPFRE": "PMPFRE",
"PMLFRE": "PMLFRE",
"PMMS": "PMMS",
"PMEFRE": "PMEFRE",
"PMEPFRE": "PMEPFRE",
"PMELFRE": "PMELFRE",
"PMELFREHD": "PMELFREHD",
"PMEMS": "PMEMS",
"UGAMS": "UGAMS"
},
"uc_usps_newapi_dom_parcel_services": {
"FCLM": "FCLM",
"FCF": "FCF",
"PMMSFRB": "PMMSFRB",
"PMMMFRB": "PMMMFRB",
"PMMLFRB": "PMMLFRB",
"PMMLFRBA": "PMMLFRBA",
"PMMS": "PMMS",
"PMMCNPT1": "PMMCNPT1",
"PMMCSPT1": "PMMCSPT1",
"PMEMS": "PMEMS",
"UGAMS": "UGAMS",
"UGAMCNPT1": "UGAMCNPT1",
"UGAMCSPT1": "UGAMCSPT1",
"BPMMP": "BPMMP",
"BPMNP": "BPMNP",
"LMNB": "LMNB",
"LMM5": "LMM5",
"LMN5": "LMN5",
"MMNB": "MMNB",
"MMM5": "MMM5",
"MMN5": "MMN5"
},
"uc_usps_newapi_intl_env_services": {
"FCLM": "FCLM",
"FCP": "FCP",
"FCF": "FCF",
"FPISMIS": "FPISMIS",
"PMIIFRE": "PMIIFRE",
"PMIMIPFRE": "PMIMIPFRE",
"PMIIS": "PMIIS",
"PMIMIS": "PMIMIS",
"PMIILFRE": "PMIILFRE",
"PMEIIFRE": "PMEIIFRE",
"PMEIILFRE": "PMEIILFRE",
"PMEIIS": "PMEIIS",
"PMEIIPFRE": "PMEIIPFRE"
},
"uc_usps_newapi_intl_parcel_services": {
"FPISMIS": "FPISMIS",
"PMIMILFRB": "PMIMILFRB",
"PMIMIMFRB": "PMIMIMFRB",
"PMIIS": "PMIIS",
"PMIMIS": "PMIMIS",
"PMEIIS": "PMEIIS"
}
}
Loading