Laravel USPS by John Paul Medina is a full-featured Laravel package wrapping the USPS API v3 — a modern OAuth2-authenticated REST/JSON API.
The package covers 20 API domains and 80+ endpoints, including address validation, package tracking, shipping labels, pricing, and carrier pickup scheduling. Under the hood it handles OAuth2 token management automatically, caching tokens for roughly 50 minutes to cut down on unnecessary auth requests.
Installation
composer require johnpaulmedina/laravel-usps
Publish the config file:
php artisan vendor:publish --tag=usps-config
Then add your USPS OAuth2 credentials to .env. You can obtain these from the USPS Developer Portal:
USPS_CLIENT_ID=your-client-idUSPS_CLIENT_SECRET=your-client-secret
Address Validation
Address validation is one of the most common use cases. The Usps facade exposes a validate() method that accepts a plain array of address fields and returns a standardized, corrected address along with DPV (Delivery Point Validation) confirmation:
use Johnpaulmedina\Usps\Facades\Usps; $result = Usps::validate([ 'Address' => '78 NW 37th St', 'City' => 'Miami', 'State' => 'FL', 'Zip' => '33127',]);
On success, the response contains the corrected address along with additional Delivery Point Validation (DPV) info:
{ "address": { "Address2": "78 NW 37TH ST", "City": "MIAMI", "State": "FL", "Zip5": "33127", "Zip4": "3178" }, "additionalInfo": { "deliveryPoint": "00", "carrierRoute": "C000", "DPVConfirmation": "Y", "DPVCMRA": "N", "business": "N", "centralDeliveryPoint": "N", "vacant": "N" }}
DPVConfirmation confirms whether the address is a real USPS deliverable location: Y for a full match, D if a secondary unit (apartment/suite) is missing, S if the secondary unit doesn't match, and N if the address isn't a valid delivery point.
If corrections were made to the submitted address, a corrections key will also be present in the response.
Input Normalization
All inputs are automatically normalized before being sent to the USPS API — state names (including territories and military codes) are converted to two-letter abbreviations, ZIP+4 strings are split into their components, country names are converted to ISO alpha-2 codes, and dates are normalized to ISO 8601 format:
Usps::validate([ 'Address' => '78 NW 37th St', 'City' => 'Miami', 'State' => 'Florida', // converted to 'FL' 'Zip' => '33127-3178', // split into Zip5: 33127, Zip4: 3178]);
For the reverse lookup — getting a city and state from a ZIP code — there's cityStateLookup():
$result = Usps::cityStateLookup('33127');
{ "city": "MIAMI", "state": "FL", "zip": "33127"}
Package Tracking
Tracking is accessed through a fluent sub-client. Call tracking() on the facade to get a Tracking instance, then call track() with an array of tracking request objects. The USPS API supports up to 35 shipments in a single request:
$result = Usps::tracking()->track([ ['trackingNumber' => '9400111899223456789012'], ['trackingNumber' => '9400111899223456789099'],]);
The response includes current status, location, and delivery information for each shipment:
{ "trackingNumber": "9400111899223456789012", "status": "Delivered", "statusSummary": "Your item was delivered at 11:23 am on March 28, 2026 in MIAMI, FL 33127.", "trackSummary": { "event": "Delivered, Front Door/Porch", "eventDate": "March 28, 2026", "eventTime": "11:23 am", "eventCity": "MIAMI", "eventState": "FL", "eventZIPCode": "33127" }}
If you need to register email alerts for a shipment, the same Tracking instance has a registerNotifications() method that accepts a tracking number and notification preferences.
Artisan Commands
The package ships with a handful of convenient Artisan commands for quick lookups without writing any code:
# Validate an addressphp artisan usps:validate "78 NW 37TH ST" --state=FL --zip=33127 # Track a packagephp artisan usps:track 9400111899223456789012 # Look up a ZIP codephp artisan usps:zip 33127
Address validation and tracking are just two of the twenty API domains the package covers. You can also generate domestic and international shipping labels, calculate rates, schedule carrier pickups, manage disputes, and more — all through the same facade-based interface.
You can find the source on GitHub and the full documentation at johnpaulmedina.github.io/laravel-usps.