PHPackages                             johnpaulmedina/laravel-usps - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Validation &amp; Sanitization](/categories/validation)
4. /
5. johnpaulmedina/laravel-usps

ActiveLibrary[Validation &amp; Sanitization](/categories/validation)

johnpaulmedina/laravel-usps
===========================

USPS Addresses API v3 (OAuth2) for Laravel

v13.4.1(3mo ago)4023.1k↑138.2%32[2 PRs](https://github.com/johnpaulmedina/laravel-usps/pulls)MITPHPPHP ^8.1CI passing

Since Mar 25Pushed 6d ago6 watchersCompare

[ Source](https://github.com/johnpaulmedina/laravel-usps)[ Packagist](https://packagist.org/packages/johnpaulmedina/laravel-usps)[ Docs](https://github.com/johnpaulmedina/laravel-usps/)[ RSS](/packages/johnpaulmedina-laravel-usps/feed)WikiDiscussions main Synced today

READMEChangelog (10)Dependencies (8)Versions (139)Used By (0)

Laravel-USPS
============

[](#laravel-usps)

Full Laravel package for the **USPS API v3** (OAuth2). Covers all 20 USPS API domains: addresses, tracking, labels, international labels, domestic prices, international prices, service standards, locations, carrier pickup, containers, payments, campaigns, package campaigns, adjustments, disputes, appointments, shipping options, and SCAN forms.

> **Note:** The legacy USPS Web Tools XML API was retired in January 2026. This package uses the new OAuth2-based REST/JSON API at `apis.usps.com`.

> **Reference:** Official USPS API examples and OpenAPI specs at [github.com/USPS/api-examples](https://github.com/USPS/api-examples).

Requirements
------------

[](#requirements)

- PHP 8.1+
- Laravel 10, 11, 12, or 13
- USPS API credentials from [developer.usps.com](https://developer.usps.com)

Installation
------------

[](#installation)

```
composer require johnpaulmedina/laravel-usps
```

The service provider and facade are auto-discovered.

Configuration
-------------

[](#configuration)

Publish the config file:

```
php artisan vendor:publish --tag=usps-config
```

This creates `config/usps.php`:

```
return [
    'client_id' => env('USPS_CLIENT_ID', ''),
    'client_secret' => env('USPS_CLIENT_SECRET', ''),
];
```

Add your credentials to `.env`:

```
USPS_CLIENT_ID=your-client-id
USPS_CLIENT_SECRET=your-client-secret

```

Artisan Commands
----------------

[](#artisan-commands)

```
# Validate an address
php artisan usps:validate "1600 Pennsylvania Ave NW" --state=DC --zip=20500

# Track packages
php artisan usps:track 9400111899223456789012

# ZIP code lookup (city/state)
php artisan usps:zip 33101

# Calculate shipping rates
php artisan usps:price 20500 33101 16 --mail-class=PRIORITY_MAIL

# Delivery estimates
php artisan usps:standards 20500 33101

# Find USPS locations
php artisan usps:locations 33101 --type=post-office --radius=5
```

All commands output formatted tables to the console.

Usage
-----

[](#usage)

All API domains are accessible via the `Usps` facade. Address methods are called directly; all other domains are accessed through fluent accessor methods that return typed API clients.

### Addresses

[](#addresses)

```
use Usps;

// Validate an address
$result = Usps::validate([
    'Address' => '1600 Pennsylvania Ave NW',
    'City' => 'Washington',
    'State' => 'DC',
    'Zip' => '20500',
]);
```

**Response:**

```
{
    "address": {
        "Address2": "1600 PENNSYLVANIA AVE NW",
        "Address1": "",
        "City": "WASHINGTON",
        "State": "DC",
        "Zip5": "20500",
        "Zip4": "0005"
    },
    "additionalInfo": {
        "deliveryPoint": "00",
        "carrierRoute": "C000",
        "DPVConfirmation": "Y",
        "DPVCMRA": "N",
        "business": "Y",
        "centralDeliveryPoint": "",
        "vacant": "N"
    }
}
```

> **DPV (Delivery Point Validation)** confirms whether a specific address is a real USPS deliverable location — down to the apartment/suite level.
>
> CodeMeaning`Y`Full match — both street and unit confirmed`D`Primary address confirmed, apartment/suite **missing**`S`Primary confirmed, apartment/suite provided but **doesn't match**`N`Not a valid delivery point

**When apartment is missing (e.g., multi-unit building):**

```
{
    "address": {
        "Address2": "100 S BISCAYNE BLVD",
        "Address1": "",
        "City": "MIAMI",
        "State": "FL",
        "Zip5": "33131",
        "Zip4": "2011"
    },
    "corrections": [
        {
            "code": "32",
            "text": "Default address: The address you entered was found but more information is needed (such as an apartment, suite, or box number) to match to a specific address."
        }
    ],
    "additionalInfo": {
        "deliveryPoint": "99",
        "carrierRoute": "C038",
        "DPVConfirmation": "D",
        "DPVCMRA": "N",
        "business": "N",
        "centralDeliveryPoint": "",
        "vacant": "N"
    }
}
```

> **Correction codes:** `32` = apartment/suite needed, `22` = multiple addresses found.

```
// Full address lookup (raw v3 response)
$result = Usps::addressLookup([
    'streetAddress' => '1600 Pennsylvania Ave NW',
    'city' => 'Washington',
    'state' => 'DC',
]);
```

**Response:**

```
{
    "firm": "",
    "address": {
        "streetAddress": "1600 PENNSYLVANIA AVE NW",
        "streetAddressAbbreviation": "1600 PENNSYLVANIA AVE NW",
        "secondaryAddress": "",
        "cityAbbreviation": "WASHINGTON",
        "city": "WASHINGTON",
        "state": "DC",
        "ZIPCode": "20500",
        "ZIPPlus4": "0005",
        "urbanization": ""
    },
    "additionalInfo": { ... },
    "corrections": [],
    "matches": [{ "code": "31", "text": "Single Response - exact match" }]
}
```

```
// City/State lookup by ZIP
$result = Usps::cityStateLookup('20500');
```

**Response:**

```
{
    "city": "WASHINGTON",
    "state": "DC",
    "ZIPCode": "20500"
}
```

```
// ZIP Code lookup by address
$result = Usps::zipCodeLookup([
    'streetAddress' => '1600 Pennsylvania Ave NW',
    'city' => 'Washington',
    'state' => 'DC',
]);
```

**Response:**

```
{
    "firm": "",
    "address": {
        "streetAddress": "1600 PENNSYLVANIA AVE NW",
        "city": "WASHINGTON",
        "state": "DC",
        "ZIPCode": "20500",
        "ZIPPlus4": "0005"
    }
}
```

> **Note:** State names are auto-converted to abbreviations (`Florida` → `FL`). ZIP codes with dashes are auto-split (`20500-0005` → ZIP5: `20500`, ZIP4: `0005`).

> **USPS Address API Documentation:** [developer.usps.com/api/81](https://developer.usps.com/api/81) — full response field definitions, DPV codes, correction codes, and error handling.

### Tracking

[](#tracking)

```
// Track packages (supports up to 35 at once)
$result = Usps::tracking()->track([
    ['trackingNumber' => '9400111899223456789012'],
]);

// Register for email notifications
Usps::tracking()->registerNotifications('9400111899223456789012', [
    'uniqueTrackingID' => 'abc-123',
    'notifyEventTypes' => ['ALL_UPDATES'],
    'recipients' => [['email' => 'user@example.com']],
]);

// Request proof of delivery
Usps::tracking()->proofOfDelivery('9400111899223456789012', [
    'uniqueTrackingID' => 'abc-123',
    'recipients' => [['email' => 'user@example.com', 'firstName' => 'John', 'lastName' => 'Doe']],
]);
```

### Domestic Labels

[](#domestic-labels)

```
// Create a shipping label (requires payment authorization token)
$label = Usps::labels()->createLabel($labelData, $paymentToken);
$label = Usps::labels()->createLabel($labelData, $paymentToken, 'idempotency-key');

// Create a return label
$label = Usps::labels()->createReturnLabel($labelData, $paymentToken);

// Cancel/refund a label
Usps::labels()->cancelLabel('9205500000000000000000');

// Edit label attributes
Usps::labels()->editLabel('9205500000000000000000', $patchData);

// First-Class indicia
Usps::labels()->createIndicia($indiciaData, $paymentToken);

// Intelligent Mail Barcode
Usps::labels()->createImb($imbData, $paymentToken);
Usps::labels()->cancelImb('00000000000000000000');

// Label branding
Usps::labels()->uploadBranding($svgData);
Usps::labels()->listBranding(limit: 10, offset: 0);
Usps::labels()->getBranding('image-uuid');
Usps::labels()->deleteBranding('image-uuid');
Usps::labels()->renameBranding('image-uuid', ['name' => 'new-name']);

// Reprint a label
Usps::labels()->reprintLabel('9205500000000000000000', $reprintData, $paymentToken);
```

### International Labels

[](#international-labels)

```
$label = Usps::internationalLabels()->createLabel($labelData, $paymentToken);
Usps::internationalLabels()->reprintLabel('CX123456789US', $reprintData, $paymentToken);
Usps::internationalLabels()->cancelLabel('CX123456789US');
Usps::internationalLabels()->createIndicia($indiciaData, $paymentToken);
```

### Domestic Prices

[](#domestic-prices)

```
// Base rate search
$rate = Usps::domesticPrices()->baseRateSearch([
    'originZIPCode' => '20500',
    'destinationZIPCode' => '33101',
    'weight' => 2.5,
    'mailClass' => 'PRIORITY_MAIL',
]);

// Extra service rate search
$rate = Usps::domesticPrices()->extraServiceRateSearch($rateIngredients);

// List eligible products
$list = Usps::domesticPrices()->baseRateListSearch($rateIngredients);

// Total rates (base + extra services)
$total = Usps::domesticPrices()->totalRateSearch($rateIngredients);

// First-Class letter rates
$letter = Usps::domesticPrices()->letterRateSearch($rateIngredients);
```

### International Prices

[](#international-prices)

```
$rate = Usps::internationalPrices()->baseRateSearch($rateIngredients);
$rate = Usps::internationalPrices()->extraServiceRateSearch($rateIngredients);
$list = Usps::internationalPrices()->baseRateListSearch($rateIngredients);
$total = Usps::internationalPrices()->totalRateSearch($rateIngredients);
$letter = Usps::internationalPrices()->letterRateSearch($rateIngredients);
```

### Service Standards

[](#service-standards)

```
// Delivery estimates (with dates and acceptance locations)
$estimates = Usps::serviceStandards()->getEstimates('20500', '33101', [
    'mailClass' => 'PRIORITY_MAIL',
]);

// Service standards (average delivery days)
$standards = Usps::serviceStandards()->getStandards('20500', '33101');
```

### Service Standards Directory

[](#service-standards-directory)

```
// Get valid 5-digit ZIP codes
$zips = Usps::serviceStandardsDirectory()->getValidZip5Codes();

// Get directory report (paginated)
$report = Usps::serviceStandardsDirectory()->getReport([
    'originZIPCode' => '230',
    'destinationZIPCode' => '330',
    'responseFormat' => '3D_BASE',
    'mailClass' => 'PERIODICALS',
    'limit' => 10000,
]);
```

### Service Standards Files

[](#service-standards-files)

```
// List available files
$files = Usps::serviceStandardsFiles()->listFiles();

// Get a signed download URL
$download = Usps::serviceStandardsFiles()->generateSignedUrl('Combined_Service_Standard_Directory_MKT');
```

### International Service Standards

[](#international-service-standards)

```
$standard = Usps::internationalServiceStandards()->getServiceStandard('CA', 'PRIORITY_MAIL_INTERNATIONAL');
// Returns: { countryCode, mailClass, serviceStandardMessage }
```

### Locations

[](#locations)

```
// Dropoff locations for destination entry parcels
$locations = Usps::locations()->getDropoffLocations('33101', [
    'mailClass' => 'PARCEL_SELECT',
]);

// Post office locations
$offices = Usps::locations()->getPostOfficeLocations([
    'ZIPCode' => '33101',
    'radius' => 10,
]);

// Parcel locker locations
$lockers = Usps::locations()->getParcelLockerLocations(['ZIPCode' => '33101']);
```

### Carrier Pickup

[](#carrier-pickup)

```
// Check pickup eligibility
$eligible = Usps::carrierPickup()->checkEligibility('123 Main St', [
    'ZIPCode' => '33101',
    'state' => 'FL',
]);

// Schedule a pickup
$pickup = Usps::carrierPickup()->schedulePickup([
    'pickupDate' => '2026-04-01',
    'pickupAddress' => [...],
    'packages' => [['packageType' => 'PRIORITY_MAIL', 'packageCount' => 2]],
    'estimatedWeight' => 5.0,
    'pickupLocation' => ['packageLocation' => 'FRONT_DOOR'],
]);

// Get, update, cancel
$details = Usps::carrierPickup()->getPickup('WTC12345');
Usps::carrierPickup()->updatePickup('WTC12345', $data, $etag);
Usps::carrierPickup()->cancelPickup('WTC12345', $etag);
```

### Containers

[](#containers)

```
// Create a container label
$container = Usps::containers()->createContainer($containerData);

// Add/remove packages
Usps::containers()->addPackages('CNT-001', ['trackingNumbers' => [...]]);
Usps::containers()->removePackage('CNT-001', '9400111899223456789012');
Usps::containers()->removeAllPackages('CNT-001');

// Close container and generate manifest
Usps::containers()->createManifest(['containers' => ['CNT-001']]);
```

### Payments

[](#payments)

```
// Create payment authorization token (required for labels)
$auth = Usps::payments()->createPaymentAuthorization([
    'roles' => [
        ['roleName' => 'PAYER', 'CRID' => '12345678', 'accountType' => 'EPS', 'accountNumber' => '1234'],
        ['roleName' => 'LABEL_OWNER', 'CRID' => '12345678', 'MID' => '123456', 'manifestMID' => '123456'],
    ],
]);
$token = $auth['paymentAuthorizationToken'];

// Check account balance
$account = Usps::payments()->getPaymentAccount('12345678', 'EPS', ['amount' => 50.00]);
```

### Informed Delivery Campaigns (Mail)

[](#informed-delivery-campaigns-mail)

```
$campaign = Usps::campaigns()->createCampaign($campaignData);
$list = Usps::campaigns()->searchCampaigns(['status' => 'ACTIVE']);
$detail = Usps::campaigns()->getCampaign('CAM-001');
Usps::campaigns()->updateCampaign('CAM-001', $data);
Usps::campaigns()->cancelCampaign('CAM-001');
Usps::campaigns()->addImbs('CAM-001', ['imbs' => [...]]);

// Callback key management
$keys = Usps::campaigns()->getCallbackKeys('12345');
$summary = Usps::campaigns()->getCallbackSummary('12345', 'key-abc');
$details = Usps::campaigns()->getCallbackDetails('12345', 'key-abc');
```

### Informed Delivery Package Campaigns

[](#informed-delivery-package-campaigns)

```
$campaign = Usps::packageCampaigns()->createCampaign($campaignData);
$list = Usps::packageCampaigns()->searchCampaigns();
$detail = Usps::packageCampaigns()->getCampaign('PKG-001');
Usps::packageCampaigns()->updateCampaign('PKG-001', $data);
Usps::packageCampaigns()->cancelCampaign('PKG-001');
Usps::packageCampaigns()->addTrackingNumbers('PKG-001', ['trackingNumbers' => [...]]);
```

### Adjustments

[](#adjustments)

```
$adjustments = Usps::adjustments()->getAdjustments('12345678', '920011234561234567890', 'CENSUS');
$adjustments = Usps::adjustments()->getAdjustments('12345678', '920011234561234567890', 'DUPLICATES', [
    'destinationZIPCode' => '33101',
]);
```

### Disputes

[](#disputes)

```
$dispute = Usps::disputes()->createDispute([
    'EPSTransactionID' => 'TXN-001',
    'trackingID' => '920011234561234567890',
    'CRID' => '12345678',
    'reason' => 'INCORRECT_ASSESSED_WEIGHT',
    'description' => 'Weight was measured incorrectly.',
    'name' => 'John Doe',
    'disputeCount' => '1',
]);
```

### Appointments (FAST)

[](#appointments-fast)

```
// Check availability
$slots = Usps::appointments()->getAvailability(['facilityId' => 'FAC-001']);

// Create, update, cancel
$appt = Usps::appointments()->createAppointment($appointmentData);
Usps::appointments()->updateAppointment($updateData);
Usps::appointments()->cancelAppointment(['appointmentId' => 'APT-001']);
```

### Shipping Options

[](#shipping-options)

```
// Combined pricing + service standards + available options in one call
$options = Usps::shippingOptions()->search([
    'originZIPCode' => '20500',
    'destinationZIPCode' => '33101',
    'weight' => 2.5,
    'length' => 12,
    'width' => 8,
    'height' => 4,
    'mailClass' => 'PRIORITY_MAIL',
]);
```

### SCAN Forms

[](#scan-forms)

```
// Label shipment — link tracking numbers to a single EFN
$form = Usps::scanForms()->createLabelShipment([
    'trackingNumbers' => ['9400111899223456789012', '9400111899223456789013'],
]);

// MID shipment
$form = Usps::scanForms()->createMidShipment([
    'MID' => '123456',
    'trackingNumbers' => ['9400111899223456789012'],
]);

// Manifest MID shipment
$form = Usps::scanForms()->createManifestMidShipment([
    'manifestMID' => '654321',
    'MID' => '123456',
]);
```

API Domains
-----------

[](#api-domains)

DomainFacade AccessorEndpointsAddressesDirect methods3Tracking`tracking()`3Domestic Labels`labels()`12International Labels`internationalLabels()`4Domestic Prices`domesticPrices()`5International Prices`internationalPrices()`5Service Standards`serviceStandards()`2Service Standards Directory`serviceStandardsDirectory()`2Service Standards Files`serviceStandardsFiles()`2International Service Standards`internationalServiceStandards()`1Locations`locations()`3Carrier Pickup`carrierPickup()`5Containers`containers()`5Payments`payments()`2Campaigns`campaigns()`9Package Campaigns`packageCampaigns()`6Adjustments`adjustments()`1Disputes`disputes()`1Appointments`appointments()`4Shipping Options`shippingOptions()`1SCAN Forms`scanForms()`3Authentication
--------------

[](#authentication)

The package automatically handles OAuth2 client credentials flow. Access tokens are cached per-scope for ~50 minutes to minimize token requests. Each API domain requests only the scopes it needs.

License
-------

[](#license)

MIT

###  Health Score

56

—

FairBetter than 97% of packages

Maintenance91

Actively maintained with recent releases

Popularity39

Limited adoption so far

Community20

Small or concentrated contributor base

Maturity61

Established project with proven stability

 Bus Factor1

Top contributor holds 77.8% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~100 days

Recently: every ~0 days

Total

30

Last Release

102d ago

Major Versions

7.0.2 → 8.0.x-dev2022-05-14

v8.0 → v9.02022-05-14

5.4.x-dev → v10.02023-06-30

v10.0 → v11.0.x-dev2025-01-13

v11.0 → v13.02026-03-25

PHP version history (9 changes)5.2.x-devPHP &gt;=5.4.0

v1.0.0PHP &gt;=7.1.0

6.0PHP ^7.2

7.0PHP ^7.2.5

8.0.x-devPHP ^7.3|^8.0

v9.0PHP ^8.0.2

5.4.x-devPHP &gt;=5.6.4

v10.0PHP ^8.1

v11.0.x-devPHP ^8.2

### Community

Maintainers

![](https://www.gravatar.com/avatar/93db769fc9a578d0b75ab6db17c2f260785b428475478ead1708524911935ee1?d=identicon)[johnpaulmedina](/maintainers/johnpaulmedina)

---

Top Contributors

[![johnpaulmedina](https://avatars.githubusercontent.com/u/1139439?v=4)](https://github.com/johnpaulmedina "johnpaulmedina (42 commits)")[![pdbreen](https://avatars.githubusercontent.com/u/1670907?v=4)](https://github.com/pdbreen "pdbreen (7 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (3 commits)")[![bredmor](https://avatars.githubusercontent.com/u/8249823?v=4)](https://github.com/bredmor "bredmor (1 commits)")[![neodisco](https://avatars.githubusercontent.com/u/15376698?v=4)](https://github.com/neodisco "neodisco (1 commits)")

---

Tags

address-validationlaravellaravel-packagelaravel13uspsusps-apiusps-migrationusps-v3laravelvalidationaddressoauth2uspsapi v3

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/johnpaulmedina-laravel-usps/health.svg)

```
[![Health](https://phpackages.com/badges/johnpaulmedina-laravel-usps/health.svg)](https://phpackages.com/packages/johnpaulmedina-laravel-usps)
```

###  Alternatives

[spatie/laravel-responsecache

Speed up a Laravel application by caching the entire response

2.8k9.0M69](/packages/spatie-laravel-responsecache)[laravel/pulse

Laravel Pulse is a real-time application performance monitoring tool and dashboard for your Laravel application.

1.7k15.1M132](/packages/laravel-pulse)[psalm/plugin-laravel

Psalm plugin for Laravel

3355.3M346](/packages/psalm-plugin-laravel)[mike-bronner/laravel-model-caching

Automatic caching for Eloquent models.

2.4k91.9k1](/packages/mike-bronner-laravel-model-caching)[roots/acorn

Framework for Roots WordPress projects built with Laravel components.

9762.4M131](/packages/roots-acorn)[sandermuller/laravel-fluent-validation

Fluent validation rule builders for Laravel

20719.0k4](/packages/sandermuller-laravel-fluent-validation)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
