Download the PHP package amdadulhaq/bd-courier-laravel without Composer
On this page you can find all versions of the php package amdadulhaq/bd-courier-laravel. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download amdadulhaq/bd-courier-laravel
More information about amdadulhaq/bd-courier-laravel
Files in amdadulhaq/bd-courier-laravel
Package bd-courier-laravel
Short Description Create shipments and track parcels from Laravel via popular Bangladeshi courier services (Pathao, Steadfast, RedX, eCourier, Paperfly, Sundarban, SA Paribahan, Karatoa), behind one driver-based API.
License MIT
Homepage https://github.com/amdad121/bd-courier-laravel
Informations about the package bd-courier-laravel
BD Courier for Laravel
Create shipments and track parcels from Laravel via popular Bangladeshi courier services (Pathao, Steadfast, RedX, eCourier, Paperfly, Sundarban, SA Paribahan, Karatoa), all behind one driver-based API.
Contents
- Requirements
- Installation
- Configuration
- Which driver do I need?
- Booking a shipment
- Handling webhooks
- API reference
- Adding your own courier
- Testing
- Troubleshooting
- Running the package's own test suite
- License
Requirements
- PHP 8.2, 8.3, 8.4, or 8.5
- Laravel 11, 12, or 13
Installation
The service provider and Courier facade are auto-discovered. Publish the config file:
Configuration
Set the default driver and credentials in your .env:
steadfast has the simplest signup of the bunch, so it's the default — start there if you don't have merchant credentials for anything else yet.
Or, for Pathao:
Or, for RedX:
Or, for eCourier:
Or, for Paperfly:
Or, for Sundarban:
Or, for SA Paribahan:
Or, for Karatoa:
See config/courier.php for every driver's options. COURIER_DRIVER defaults to steadfast.
Which driver do I need?
| Driver | Cancel shipment? | Price calculator? | Server-to-server webhook? | Notes |
|---|---|---|---|---|
pathao |
No | Yes | No (poll/track instead) | Requires an issued OAuth token; auto-renewed and cached. |
steadfast |
No | No | No (poll/track instead) | Simplest signup, popular with small merchants. |
redx |
Yes | Yes | No (poll/track instead) | |
ecourier |
No | No | No (poll/track instead) | |
paperfly |
No | No | No (poll/track instead) | |
sundarban |
No | No | No (poll/track instead) | |
sa_paribahan |
No | No | No (poll/track instead) | |
karatoa |
Yes | No | No (poll/track instead) |
Every driver throws AmdadulHaq\BdCourier\Exceptions\CourierException for operations it doesn't support, so calling code can rely on the same contract regardless of which courier is active.
Booking a shipment
Track a shipment any time without mutating anything:
Cancel a shipment (not every courier/driver supports this):
Estimate the delivery fee before booking (not every courier/driver supports this):
Use a specific driver, or a driver other than the default, for one call — same as Storage::disk():
Handling webhooks
Some couriers notify your server directly with status updates instead of (or in addition to) you polling track(). Point that URL at a route in your app and hand the request straight to the driver:
None of the couriers supported out of the box sign their webhook payload, so every driver treats the incoming payload as a hint at most: it extracts the consignment/tracking ID and calls the courier's own track() endpoint to get the real, authoritative status rather than trusting the payload directly. Drivers with no webhook mechanism at all throw AmdadulHaq\BdCourier\Exceptions\CourierException.
API reference
ShipmentRequest
Everything a driver might need to book a shipment — pass what applies, ignore the rest (e.g. drivers without a price calculator ignore fields they don't read).
| Property | Type | Notes |
|---|---|---|
invoiceNumber |
string |
Required. Your own unique reference — becomes merchant_order_id (Pathao), invoice (Steadfast), merchant_invoice_id (RedX), etc. |
recipientName |
string |
Required. |
recipientPhone |
string |
Required. |
recipientAddress |
string |
Required. Full delivery address. |
recipientCity, recipientZone, recipientArea |
string |
District/thana/area — required by drivers that route by zone (Pathao, RedX). Defaults to '' for drivers that parse the full address instead. |
codAmount |
float |
Cash-on-delivery amount to collect. Defaults to 0.0 for prepaid parcels. |
itemWeight |
float |
In kilograms. Defaults to 0.5. |
itemDescription |
string |
Defaults to ''. |
itemQuantity |
int |
Defaults to 1. |
specialInstruction |
?string |
Delivery notes passed through to the courier where supported. |
metadata |
array<string, mixed> |
Driver-specific extras not covered above. |
ShipmentResponse
What every driver method returns, so calling code never branches on which courier answered.
| Property | Type | Meaning |
|---|---|---|
status |
ShipmentStatus |
Normalized status — see below. |
invoiceNumber |
string |
Echoes back your invoice/reference. |
consignmentId |
?string |
The courier's own tracking/consignment ID — save this, you'll need it for track()/cancel(). |
trackingUrl |
?string |
A public tracking link/code, when the courier returns one. |
deliveryFee |
?float |
The confirmed or quoted delivery charge, when the courier reports one. |
message |
?string |
Human-readable status text from the courier. |
raw |
array<string, mixed> |
The untouched courier response — keep this for auditing/debugging, don't build logic on it directly. |
ShipmentStatus
| Case | Meaning |
|---|---|
Pending |
Booked, not yet picked up. |
PickupRequested |
Pickup scheduled with the rider/hub. |
PickedUp |
Rider has collected the parcel. |
InTransit |
Parcel is moving between hubs / out for delivery. |
Delivered |
Delivered and (if COD) collected — $status->isSuccessful() is true. |
PartialDelivered |
Only part of the order was accepted/delivered. |
Returned |
Parcel came back to the merchant. |
Cancelled |
Shipment was cancelled before/after booking. |
Failed |
Delivery attempt failed, or the courier reported an unrecognized status. |
$status->isFinal() is true for every case except Pending, PickupRequested, PickedUp, and InTransit.
Adding your own courier
Register a custom driver:
Any driver just needs to implement AmdadulHaq\BdCourier\Contracts\CourierDriver:
Testing
Use CourierManager::fake() to swap the real courier with an in-memory fake and assert on what would have been booked, without dispatching anything or hitting the network:
Troubleshooting
Pathao: "Failed to issue an access token."
Double-check PATHAO_USERNAME/PATHAO_PASSWORD (your Pathao Merchant Panel credentials, not a courier account PIN) and that PATHAO_BASE_URL matches your environment — the sandbox and production base URLs are different hosts, not just different credentials.
Steadfast / RedX / others: createShipment() throws a gateway error with no useful message
Most of these couriers return a generic HTTP 4xx with the real reason buried in the JSON body. Catch AmdadulHaq\BdCourier\Exceptions\CourierException and inspect $exception->context — it holds the courier's raw decoded response.
A webhook route never fires handleWebhook()
Make sure the route excludes Laravel's CSRF middleware (none of these couriers can obtain a CSRF token) and that you're passing the entire raw POST payload — $request->all() — since each driver looks for a specific ID field (consignment_id, tracking_id, tracking_number, etc.) that varies by courier.
"Nothing happens" in local development
COURIER_DRIVER defaults to steadfast. If you're expecting a different courier, confirm .env actually sets COURIER_DRIVER and that you ran php artisan config:clear after changing it (cached config wins over .env).
Running the package's own test suite
License
MIT. See LICENSE.md.
All versions of bd-courier-laravel with dependencies
illuminate/http Version ^11.0|^12.0|^13.0
illuminate/support Version ^11.0|^12.0|^13.0