pralhadstha / nepalcan-laravel
Laravel integration for Nepal Can Move (NCM) courier API — shipments, tracking, rates, webhooks, COD, and delivery management for Nepal
Requires
- php: ^8.1
- illuminate/contracts: ^10.0|^11.0|^12.0
- illuminate/http: ^10.0|^11.0|^12.0
- illuminate/support: ^10.0|^11.0|^12.0
- pralhadstha/nepal-can-php-sdk: ^1.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.0
- larastan/larastan: ^2.0|^3.0
- orchestra/testbench: ^8.0|^9.0|^10.0
- phpstan/phpstan: ^1.0
- phpunit/phpunit: ^10.0|^11.0
README
Laravel integration for the Nepal Can Move (NCM) courier and shipping API. Manage shipments, track deliveries, calculate rates, handle COD payments, and process webhooks — all with idiomatic Laravel patterns.
Built on top of Nepal Can PHP SDK.
Features
- Service Provider with auto-discovery — zero configuration to get started
- Facade (
NepalCan) for clean, expressive syntax - Dependency Injection — type-hint
OmniCargo\NepalCan\Clientin any class - Publishable Config — environment-based API token and base URL management
- Webhook Integration — automatic route registration with Laravel event dispatching
- Webhook Middleware — user-agent validation out of the box
- Laravel Events — listen for delivery status changes with native event listeners
Requirements
| Dependency | Version |
|---|---|
| PHP | ^8.1 |
| Laravel | 10.x, 11.x, or 12.x |
Installation
composer require pralhadstha/nepalcan-laravel
The service provider and facade are auto-discovered. No manual registration needed.
Publish Configuration
php artisan vendor:publish --tag=nepalcan-config
This creates config/nepalcan.php in your application.
Configuration
Add these variables to your .env file:
NEPALCAN_API_TOKEN=your-api-token-here NEPALCAN_ENVIRONMENT=sandbox
Environment Variables
| Variable | Description | Default |
|---|---|---|
NEPALCAN_API_TOKEN |
Your NCM API token from the dashboard | "" |
NEPALCAN_ENVIRONMENT |
sandbox or production |
sandbox |
NEPALCAN_BASE_URL |
Override the API base URL entirely | null |
NEPALCAN_WEBHOOK_VALIDATE_UA |
Validate webhook User-Agent header | true |
NEPALCAN_WEBHOOK_PATH |
Webhook endpoint path | /nepalcan/webhook |
Set NEPALCAN_ENVIRONMENT=production when you're ready to go live. This switches the base URL from demo.nepalcanmove.com to nepalcanmove.com.
Usage
Using the Facade
use OmniCargo\NepalCan\Laravel\Facades\NepalCan;
Create a Shipment
$order = NepalCan::shipments()->create([ 'receiver_name' => 'Ram Shrestha', 'receiver_phone' => '9801234567', 'receiver_address' => 'Kathmandu', 'product_name' => 'Electronics', 'cod_charge' => '1500', 'quantity' => 1, ]); echo $order->orderId;
Track an Order
// By order ID $statuses = NepalCan::tracking()->getStatusHistory(12345); // By tracking ID $detail = NepalCan::tracking()->track('NCM-123456'); echo $detail->lastDeliveryStatus; // Bulk status check $bulk = NepalCan::tracking()->getBulkStatuses([12345, 67890]);
Calculate Shipping Rates
use OmniCargo\NepalCan\Services\RateService; $rate = NepalCan::rates()->calculate('Kathmandu', 'Pokhara'); echo $rate->charge; // Specify delivery type $rate = NepalCan::rates()->calculate( 'Kathmandu', 'Pokhara', RateService::TYPE_D2B, // Door to Branch );
Available delivery types: TYPE_PICKUP_COLLECT (Door2Door), TYPE_SEND (Branch2Door), TYPE_D2B (Door2Branch), TYPE_B2B (Branch2Branch).
List Branches
$branches = NepalCan::branches()->list(); foreach ($branches as $branch) { echo "{$branch->name} - {$branch->district}"; }
Support Tickets
use OmniCargo\NepalCan\Services\TicketService; // Create a ticket $ticket = NepalCan::tickets()->create( TicketService::TYPE_GENERAL, 'Need help with order #12345', ); // Request COD transfer $ticket = NepalCan::tickets()->createCodTransfer( bankName: 'Nepal Bank', accountName: 'Ram Shrestha', accountNumber: '1234567890', ); // Close a ticket NepalCan::tickets()->close($ticket->ticketId);
Staff Management
$result = NepalCan::staff()->list(search: 'ram', page: 1, pageSize: 10); foreach ($result['results'] as $staff) { echo "{$staff->name} - {$staff->email}"; }
Using Dependency Injection
You can type-hint the SDK client directly in your controllers, jobs, or any service:
use OmniCargo\NepalCan\Client; class ShippingController extends Controller { public function __construct(private readonly Client $client) { } public function show(int $orderId) { $order = $this->client->shipments->find($orderId); $history = $this->client->tracking->getStatusHistory($orderId); return view('shipping.show', compact('order', 'history')); } }
Webhook Handling
Automatic Route Registration
By default, the package registers a POST route at /nepalcan/webhook. Incoming webhook payloads are parsed and dispatched as Laravel events.
Make sure to exclude this path from CSRF verification. In Laravel 10:
// app/Http/Middleware/VerifyCsrfToken.php protected $except = [ 'nepalcan/webhook', ];
In Laravel 11+:
// bootstrap/app.php ->withMiddleware(function (Middleware $middleware) { $middleware->validateCsrfTokens(except: [ 'nepalcan/webhook', ]); })
To disable the automatic route, set NEPALCAN_WEBHOOK_PATH to an empty value or set webhook.path to null in the config.
User-Agent Validation
The package validates that incoming webhook requests have a User-Agent header starting with NCM-Webhook/. This prevents unauthorized requests from reaching your event listeners. Disable this with:
NEPALCAN_WEBHOOK_VALIDATE_UA=false
Listening for Events
Register listeners in your EventServiceProvider or use Event::listen():
use OmniCargo\NepalCan\Laravel\Events\DeliveryCompleted; use OmniCargo\NepalCan\Laravel\Events\NepalCanWebhookReceived; // Listen for a specific event Event::listen(DeliveryCompleted::class, function (DeliveryCompleted $event) { $orderId = $event->webhook->orderId; // Update your order status, notify customer, etc. }); // Listen for ALL webhook events Event::listen(NepalCanWebhookReceived::class, function (NepalCanWebhookReceived $event) { Log::info("NCM webhook: {$event->webhook->event}", [ 'order_id' => $event->webhook->orderId, 'status' => $event->webhook->status, ]); });
Available Events
Every webhook dispatches the generic NepalCanWebhookReceived event. Additionally, a specific event is dispatched based on the webhook type:
| Webhook Event | Laravel Event Class |
|---|---|
pickup_completed |
OmniCargo\NepalCan\Laravel\Events\PickupCompleted |
sent_for_delivery |
OmniCargo\NepalCan\Laravel\Events\SentForDelivery |
order_dispatched |
OmniCargo\NepalCan\Laravel\Events\OrderDispatched |
order_arrived |
OmniCargo\NepalCan\Laravel\Events\OrderArrived |
delivery_completed |
OmniCargo\NepalCan\Laravel\Events\DeliveryCompleted |
All event classes carry a public readonly Webhook $webhook property with the parsed payload data.
Testing
composer test
Or run individual suites:
vendor/bin/phpunit --testsuite=Unit vendor/bin/phpunit --testsuite=Feature
Credits
License
The MIT License (MIT). See LICENSE for details.