johnpaulmedina/laravel-usps
Composer 安装命令:
composer require johnpaulmedina/laravel-usps
包简介
USPS Addresses API v3 (OAuth2) for Laravel
README 文档
README
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.
Requirements
- PHP 8.1+
- Laravel 10, 11, 12, or 13
- USPS API credentials from developer.usps.com
Installation
composer require johnpaulmedina/laravel-usps
The service provider and facade are auto-discovered.
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
# 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
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
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.
Code Meaning YFull match — both street and unit confirmed DPrimary address confirmed, apartment/suite missing SPrimary confirmed, apartment/suite provided but doesn't match NNot 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 — full response field definitions, DPV codes, correction codes, and error handling.
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
// 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
$label = Usps::internationalLabels()->createLabel($labelData, $paymentToken); Usps::internationalLabels()->reprintLabel('CX123456789US', $reprintData, $paymentToken); Usps::internationalLabels()->cancelLabel('CX123456789US'); Usps::internationalLabels()->createIndicia($indiciaData, $paymentToken);
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
$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
// 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
// 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
// List available files $files = Usps::serviceStandardsFiles()->listFiles(); // Get a signed download URL $download = Usps::serviceStandardsFiles()->generateSignedUrl('Combined_Service_Standard_Directory_MKT');
International Service Standards
$standard = Usps::internationalServiceStandards()->getServiceStandard('CA', 'PRIORITY_MAIL_INTERNATIONAL'); // Returns: { countryCode, mailClass, serviceStandardMessage }
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
// 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
// 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
// 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)
$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
$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 = Usps::adjustments()->getAdjustments('12345678', '920011234561234567890', 'CENSUS'); $adjustments = Usps::adjustments()->getAdjustments('12345678', '920011234561234567890', 'DUPLICATES', [ 'destinationZIPCode' => '33101', ]);
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)
// 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
// 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
// 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
| Domain | Facade Accessor | Endpoints |
|---|---|---|
| Addresses | Direct methods | 3 |
| Tracking | tracking() |
3 |
| Domestic Labels | labels() |
12 |
| International Labels | internationalLabels() |
4 |
| Domestic Prices | domesticPrices() |
5 |
| International Prices | internationalPrices() |
5 |
| Service Standards | serviceStandards() |
2 |
| Service Standards Directory | serviceStandardsDirectory() |
2 |
| Service Standards Files | serviceStandardsFiles() |
2 |
| International Service Standards | internationalServiceStandards() |
1 |
| Locations | locations() |
3 |
| Carrier Pickup | carrierPickup() |
5 |
| Containers | containers() |
5 |
| Payments | payments() |
2 |
| Campaigns | campaigns() |
9 |
| Package Campaigns | packageCampaigns() |
6 |
| Adjustments | adjustments() |
1 |
| Disputes | disputes() |
1 |
| Appointments | appointments() |
4 |
| Shipping Options | shippingOptions() |
1 |
| SCAN Forms | scanForms() |
3 |
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
MIT
johnpaulmedina/laravel-usps 适用场景与选型建议
johnpaulmedina/laravel-usps 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 23.1k 次下载、GitHub Stars 达 37, 最近一次更新时间为 2016 年 05 月 12 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「address」 「oauth2」 「validation」 「laravel」 「usps」 「api-v3」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 johnpaulmedina/laravel-usps 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 johnpaulmedina/laravel-usps 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 johnpaulmedina/laravel-usps 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
Maps in minutes. Powered by the Google Maps API.
Redirects TYPO3 visitors automatic or with a suggestlink to another language and/or root page.
Module adding custom shipping attribute for what3words address
A lightweight and powerful OAuth 2.0 authorization and resource server library with support for all the core specification grants. This library will allow you to secure your API with OAuth and allow your applications users to approve apps that want to access their data from your API.
Email Toolkit Plugin for CakePHP
Adds request-parameter validation to the SLIM 3.x PHP framework
统计信息
- 总下载量: 23.1k
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 40
- 点击次数: 33
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2016-05-12