ahraihan / laravel-steadfast-courier
Steadfast Courier API (18 endpoints) and Webhook integration for Laravel
Package info
github.com/AH-Raihan/laravel-steadfast-courier
pkg:composer/ahraihan/laravel-steadfast-courier
Requires
- php: ^8.2|^8.3|^8.4
- illuminate/contracts: ^10.0|^11.0|^12.0|^13.0
- illuminate/events: ^10.0|^11.0|^12.0|^13.0
- illuminate/http: ^10.0|^11.0|^12.0|^13.0
- illuminate/routing: ^10.0|^11.0|^12.0|^13.0
- illuminate/support: ^10.0|^11.0|^12.0|^13.0
Requires (Dev)
- mockery/mockery: ^1.6
- orchestra/testbench: ^8.0|^9.0|^10.0
- pestphp/pest: ^2.0|^3.0|^5.0
- phpunit/phpunit: ^10.0|^11.0|^12.0|^13.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
A complete, battle-tested, and developer-friendly Laravel package for Steadfast Courier API (all 18 endpoints) and Webhook notifications with HMAC-SHA256 signature verification and Idempotency handling.
๐ Features
- Full API Coverage (All 18 Official Endpoints):
- Connectivity check (
ping) - Single order booking (
create_order) - Bulk orders booking (
create_order/bulk-order) - Extended bulk orders with detailed per-field validation (
create_order/bulk-order/extended) - Status tracking by Consignment ID, Tracking Code, and Merchant Invoice
- Detailed chronological tracking history timeline
- Return requests creation & pagination
- Pickup rider requests
- Real-time account balance & payout reconciliation
- Thanas / Police Stations directory
- Customer delivery record & fraud check score
- Connectivity check (
- Full Webhook Support:
- Automatic webhook route registration
- Secure HMAC-SHA256 (
X-Signature) verification with timingSafeEqual comparison Idempotency-Keytracking to eliminate duplicate event processing on Steadfast retries- Dispatches strongly-typed Laravel Events for each notification type (
delivery_status,tracking_update,consignment_update,return_list_accepted,payment_request,cancel_request,return_request,pickup_request,user_update)
- Smart Sanitization:
- Automatically strips restricted characters (
{,},;,<,>,$) according to Steadfast docs - Automatically formats Bangladeshi phone numbers (
01...) and trims fields to max lengths
- Automatically strips restricted characters (
- Clean Laravel Ergonomics:
- Facade support (
Steadfast::...andSteadfastCourier::...) - Multi-tenant / Dynamic credentials support (
withConfig(...)) - 100% backward compatibility with legacy Steadfast Courier package methods
- Facade support (
๐ฆ Requirements
- PHP
^8.2,^8.3, or^8.4 - Laravel
10.x,11.x,12.x, or13.x
๐ Installation
Install the package via Composer:
composer require ahraihan/laravel-steadfast-courier
The package uses Laravel package auto-discovery, so its Service Provider and Facade aliases are registered automatically.
Publish Configuration
Publish the config file:
php artisan vendor:publish --tag=steadfast-config
This creates config/steadfast.php.
โ๏ธ Configuration
Add your Steadfast credentials to your .env file:
# Steadfast Courier API STEADFAST_BASE_URL=https://portal.packzy.com/api/v1 STEADFAST_API_KEY=your_steadfast_api_key STEADFAST_SECRET_KEY=your_steadfast_secret_key STEADFAST_TIMEOUT=30 # Steadfast Webhook STEADFAST_WEBHOOK_ENABLED=true STEADFAST_WEBHOOK_PATH=steadfast/webhook STEADFAST_WEBHOOK_TOKEN=your_webhook_auth_token_from_steadfast STEADFAST_WEBHOOK_VERIFY_SIGNATURE=true STEADFAST_WEBHOOK_IDEMPOTENCY=true
๐ API Usage
Import the Facade into your controllers, jobs, or services:
use AhRaihan\SteadfastCourier\Facades\Steadfast;
(Note: use AhRaihan\SteadfastCourier\Facades\SteadfastCourier; is also available and 100% interchangeable).
1. Service Check (/ping)
Verify that the Steadfast server is reachable (requires no credentials).
$response = Steadfast::ping(); // ['status' => 200, 'message' => 'pong', 'service' => 'steadfast-api', 'version' => 'v1', ...]
2. Book Single Parcel (/create_order)
$response = Steadfast::createOrder([ 'invoice' => 'ORD-10231', // Required. Alphanumeric, dash, underscore only (max 100) 'recipient_name' => 'Jahid Hasan', // Required (max 100) 'recipient_phone' => '01712345678', // Required. 11 digits starting 01 'recipient_address' => 'House 17/1, Dhanmondi', // Required (max 490) 'cod_amount' => 1060, // Required. BDT (0 for prepaid) 'note' => 'Call before 3 PM', // Optional (max 480) 'alternative_phone' => '01812345678', // Optional. 11 digits starting 01 'recipient_email' => 'customer@example.com', // Optional 'item_description' => 'Books and Stationery', // Optional (max 255) 'total_lot' => 1, // Optional (default: 1) 'delivery_type' => 0, // Optional. 0 = Home Delivery (default), 1 = Point Delivery ]); $consignmentId = $response['consignment']['consignment_id'] ?? null; $trackingCode = $response['consignment']['tracking_code'] ?? null; $trackingLink = $response['consignment']['tracking_link'] ?? null;
3. Bulk Order Booking (/create_order/bulk-order)
Book up to 500 parcels in a single call.
$orders = [ [ 'invoice' => 'ORD-10231', 'recipient_name' => 'Jahid Hasan', 'recipient_phone' => '01712345678', 'recipient_address' => 'Dhanmondi, Dhaka', 'cod_amount' => 1060, ], [ 'invoice' => 'ORD-10232', 'recipient_name' => 'Nusrat Jahan', 'recipient_phone' => '01812345678', 'recipient_address' => 'Uttara, Dhaka', 'cod_amount' => 450, ], ]; $response = Steadfast::createBulkOrders($orders);
4. Extended Bulk Orders (/create_order/bulk-order/extended)
Preferred bulk booking endpoint: returns clear, human-readable per-field error sentences.
$response = Steadfast::createBulkOrdersExtended($orders);
5. Check Status by Consignment ID (/status_by_cid/{id})
$response = Steadfast::getStatusByConsignmentId(1424107); // ['status' => 200, 'delivery_status' => 'delivered']
6. Check Status with Return Status (/status_with_return_status_by_cid/{id})
Essential for stock reconciliation: reveals whether a returned parcel is back with you.
$response = Steadfast::getStatusWithReturnStatusByConsignmentId(1424107); // ['status' => 200, 'delivery_status' => 'cancelled_return_received']
7. Check Status by Invoice ID (/status_by_invoice/{invoice})
$response = Steadfast::getStatusByInvoice('ORD-10231');
8. Check Status by Tracking Code (/status_by_trackingcode/{code})
$response = Steadfast::getStatusByTrackingCode('15BAEB8A');
9. Detailed Tracking Steps History (/trackings_by_invoice/{invoice})
Shows every milestone the parcel has been through.
$response = Steadfast::getTrackingsByInvoice('ORD-10231'); foreach ($response['tracking'] as $step) { echo $step['text'].' at '.$step['created_at']; }
10. Request Rider Pickup (/create_pickup_request)
$response = Steadfast::createPickupRequest([ 'address_id' => 42, 'police_station_id' => 17, 'address' => 'House 17/1, Road 3/A, Dhanmondi', 'contact_number' => '01712345678', 'estim_qty' => 25, 'note' => 'Pick up after 2 PM', ]);
11. Request Parcel Return (/create_return_request)
$response = Steadfast::createReturnRequest([ 'invoice' => 'ORD-10231', // or 'consignment_id' or 'tracking_code' 'reason' => 'Customer changed mind before delivery', ]);
12. List Return Requests (/get_return_requests)
$response = Steadfast::getReturnRequests(page: 1);
13. Get Single Return Request (/get_return_request/{id})
$response = Steadfast::getReturnRequest(1);
14. Get Merchant Current Balance (/get_balance)
$balance = Steadfast::getCurrentBalance(); $amount = $balance['current_balance']; // e.g. 12450
15. List Payments / Payouts (/payments)
$payments = Steadfast::getPayments(page: 1);
16. Get Payment Detail with Settled Parcels (/payments/{id})
$payout = Steadfast::getPayment('SFC-88213'); // Accepts with or without SFC- prefix
17. List Police Stations / Thanas (/police_stations)
$stations = Steadfast::getPoliceStations();
18. Customer Fraud Check & Delivery Record (/fraud_check/score/{phone})
$record = Steadfast::checkFraud('01712345678'); $deliveryRatio = $record['delivery_ratio']; // Percentage delivered (e.g. 92) $cancellationRatio = $record['cancellation_ratio']; // Percentage cancelled (e.g. 7) $volumeBand = $record['volume_band']; // low, medium, high, very_high $deliveredCount = $record['delivered_count']; // Exact count (if available) $cancelledCount = $record['cancelled_count']; // Exact count (if available)
๐ Dynamic / Multi-Store Credentials
If your system supports multiple merchant accounts or stores:
$client = Steadfast::withConfig( apiKey: 'another_api_key', secretKey: 'another_secret_key', baseUrl: 'https://portal.packzy.com/api/v1', webhookToken: 'another_webhook_token' ); $balance = $client->getCurrentBalance();
๐ Webhook Integration Guide
Steadfast posts webhook events to your application when a parcel's status updates, a payout is requested, or tracking progress occurs.
1. Set Up Webhook Endpoint in Steadfast Dashboard
- Log in to your Steadfast Courier Dashboard.
- Go to Webhook settings.
- In Callback URL, enter:
https://your-domain.com/steadfast/webhook. - Click Generate next to Auth token.
- Copy the generated token and save it into your
.env:STEADFAST_WEBHOOK_TOKEN=your_generated_token_here
- Click Save webhook.
2. Exclude Webhook Route from CSRF Protection
Because Steadfast posts directly to your webhook URL, exclude it from CSRF verification:
Laravel 11 & 12 (bootstrap/app.php):
->withMiddleware(function (Middleware $middleware) { $middleware->validateCsrfTokens(except: [ 'steadfast/webhook', ]); })
Laravel 10 (app/Http/Middleware/VerifyCsrfToken.php):
protected $except = [ 'steadfast/webhook', ];
3. Listen to Webhook Events
When Steadfast triggers the webhook, the package automatically verifies the HMAC-SHA256 signature and fires the corresponding Laravel event.
Register event listeners in your EventServiceProvider or AppServiceProvider:
use AhRaihan\SteadfastCourier\Events\SteadfastDeliveryStatusChanged; use AhRaihan\SteadfastCourier\Events\SteadfastTrackingUpdated; use AhRaihan\SteadfastCourier\Events\SteadfastWebhookReceived; use Illuminate\Support\Facades\Event; public function boot(): void { // Listen for parcel delivery status changes Event::listen(SteadfastDeliveryStatusChanged::class, function (SteadfastDeliveryStatusChanged $event) { $invoice = $event->invoice; // 'ORD-10231' $consignmentId = $event->consignmentId; // 12345 $status = $event->status; // 'delivered', 'cancelled', 'partial_delivered', etc. $codAmount = $event->codAmount; // 1500.0 $deliveryCharge = $event->deliveryCharge; // 100.0 $message = $event->trackingMessage; // 'Your package has been delivered successfully.' $updatedAt = $event->updatedAt; // '2026-03-02 12:45:30' if ($event->isDelivered()) { // Update order in database to completed / mark paid } elseif ($event->isCancelled()) { // Restock items or notify support } }); // Listen to all webhook events (generic) Event::listen(SteadfastWebhookReceived::class, function (SteadfastWebhookReceived $event) { Log::info('Steadfast Webhook: ' . $event->notificationType, $event->payload); }); }
Available Webhook Events
Notification Type (notification_type) |
Laravel Event Dispatched | Description |
|---|---|---|
* (any event) |
SteadfastWebhookReceived |
General event containing raw payload & signature |
delivery_status |
SteadfastDeliveryStatusChanged |
Parcel delivery status updated |
tracking_update |
SteadfastTrackingUpdated |
New tracking step or transit milestone |
consignment_update |
SteadfastConsignmentUpdated |
Consignment updated (address, COD, etc.) |
return_list_accepted |
SteadfastReturnListAccepted |
Return list receipt confirmed |
payment_request |
SteadfastPaymentRequested |
Payout requested |
cancel_request |
SteadfastCancelRequested |
Cancellation request raised/decided |
return_request |
SteadfastReturnRequested |
Return request raised |
pickup_request |
SteadfastPickupRequested |
Pickup requested |
user_update |
SteadfastUserUpdated |
Account details updated |
๐งช Testing
Run package tests:
composer test # or vendor/bin/pest
๐ How to Publish to GitHub and Packagist
To publish this package so that anyone (or your other projects) can install it via composer require ahraihan/laravel-steadfast-courier:
-
Initialize Git inside package directory:
cd packages/ahraihan/laravel-steadfast-courier git init git add . git commit -m "feat: initial release of Steadfast Courier Laravel package"
-
Push to GitHub:
- Create a new public repository on GitHub:
https://github.com/dev-ahraihan/laravel-steadfast-courier
git remote add origin https://github.com/dev-ahraihan/laravel-steadfast-courier.git git branch -M main git push -u origin main
- Create a new public repository on GitHub:
-
Tag a Release:
git tag -a v1.0.0 -m "Release v1.0.0" git push origin v1.0.0 -
Submit to Packagist:
- Visit packagist.org and log in.
- Click Submit.
- Enter your repository URL:
https://github.com/dev-ahraihan/laravel-steadfast-courier. - Click Check and then Submit.
- Set up the GitHub Webhook on Packagist for automatic release updates!
๐ License
The MIT License (MIT). Please see LICENSE.md for more information.
๐ค Author
AH-Raihan
- Email: dev.ahraihan@gmail.com
- GitHub: @dev-ahraihan