Skip to content

pralhadstha/nepalcan-php-sdk

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Nepal Can Move (NCM) PHP SDK

PHP Version Latest Version License

A PHP SDK for integrating with the Nepal Can Move (NCM) shipping and courier API. Manage shipments, track orders, calculate delivery rates, handle COD (Cash on Delivery) payments, and receive real-time webhook notifications for your e-commerce platform in Nepal.

Table of Contents

Features

  • Shipment Management - Create, find, return, exchange, and redirect orders
  • Order Tracking - Status history and bulk status checks
  • Rate Calculation - Delivery charges for 4 delivery types (Door2Door, Branch2Door, Door2Branch, Branch2Branch)
  • Branch Listing - Get all NCM branches with contact details and covered areas
  • COD Support - Cash on delivery charge management and COD transfer tickets
  • Webhook Integration - Parse incoming webhooks with typed resources and event dispatcher
  • Support Tickets - Create and manage vendor support tickets
  • Staff Management - List and search vendor staff members
  • Type-Safe - Immutable resource objects with readonly properties
  • Well Tested - Comprehensive test suite with mocked HTTP responses
  • PSR-12 Compliant - Enforced via PHP-CS-Fixer

Requirements

  • PHP 8.1+
  • Guzzle 7.0+

Installation

composer require pralhadstha/nepal-can-php-sdk

Configuration

use OmniCargo\NepalCan\Client;
use OmniCargo\NepalCan\Config;

// Sandbox environment (default)
$client = new Client('your-api-token');

// Production environment
$client = new Client('your-api-token', Config::BASE_URL_PRODUCTION);

Note: Request your API token from NCM's IT Admin. Sandbox and production environments use separate tokens.

Usage

Branches

$branches = $client->branches->list();

foreach ($branches as $branch) {
    echo $branch->name;
    echo $branch->district;
}

Shipping Rates

use OmniCargo\NepalCan\Services\RateService;

$rate = $client->rates->calculate('TINKUNE', 'BIRATNAGAR', RateService::TYPE_PICKUP_COLLECT);

echo $rate->charge;

Available delivery types:

  • RateService::TYPE_PICKUP_COLLECT - Door2Door (NCM pickup & delivery)
  • RateService::TYPE_SEND - Branch2Door (Sender drops at branch, NCM delivers)
  • RateService::TYPE_D2B - Door2Branch (NCM picks, customer collects at branch)
  • RateService::TYPE_B2B - Branch2Branch (Sender drops at branch, customer collects)

Create Order

$order = $client->shipments->create([
    'name' => 'John Doe',
    'phone' => '9847023226',
    'cod_charge' => '2200',
    'address' => 'Byas Pokhari',
    'fbranch' => 'TINKUNE',
    'branch' => 'BIRATNAGAR',
    'package' => 'Jeans Pant',
    'vref_id' => 'VREF234',
    'instruction' => 'Handle with care',
    'delivery_type' => 'Branch2Door',
    'weight' => '2',
]);

echo $order->orderId;

Get Order Details

$order = $client->shipments->find(134);

echo $order->codCharge;
echo $order->deliveryCharge;
echo $order->lastDeliveryStatus;
echo $order->paymentStatus;

Order Comments

// Get comments for an order
$comments = $client->shipments->getComments(134);

foreach ($comments as $comment) {
    echo $comment->comments;
    echo $comment->addedBy;
}

// Get last 25 bulk comments
$comments = $client->shipments->getBulkComments();

// Add a comment
$client->shipments->addComment(1234567, 'Test comment from api');

Tracking

// Get status history for an order
$statuses = $client->tracking->getStatusHistory(134);

foreach ($statuses as $status) {
    echo $status->status;
    echo $status->addedTime;
}

// Track by tracking ID
$tracking = $client->tracking->track('8D634706B3394C3');

echo $tracking->trackId;
echo $tracking->lastDeliveryStatus;
echo $tracking->receiver;
echo $tracking->destination;

foreach ($tracking->statusHistory as $status) {
    echo $status; // "Pickup Order Created - 2026-03-23 04:43 AM"
}

// Bulk status check
$result = $client->tracking->getBulkStatuses([4041, 3855, 4032]);

// $result['result'] => ['4041' => 'Pickup Order Created', ...]
// $result['errors'] => [4042, ...] (invalid order IDs)

Returns & Exchanges

// Return an order
$client->shipments->returnOrder(4041, 'Customer refused the delivery');

// Create exchange order
$response = $client->shipments->createExchange(4041);
// $response['cust_order'] => new delivery order ID
// $response['ven_order'] => return order ID

// Redirect an order
$client->shipments->redirect(4041, [
    'name' => 'Jane Doe',
    'phone' => '9800000000',
    'address' => 'New Address',
]);

Tickets

use OmniCargo\NepalCan\Services\TicketService;

// Create a general ticket
$ticket = $client->tickets->create(TicketService::TYPE_GENERAL, 'Please arrange delivery at the earliest');

echo $ticket->ticketId;

// Create COD transfer ticket
$ticket = $client->tickets->createCodTransfer('Nepal Bank Limited', 'John Doe', '1234567890');

// Close a ticket
$client->tickets->close(123);

Available ticket types: General, Order Processing, Return, Pickup

Staff

$result = $client->staff->list(search: 'Ram', page: 1, pageSize: 20);

echo $result['count'];

foreach ($result['results'] as $staff) {
    echo $staff->name;
    echo $staff->email;
    echo $staff->phone;
}

Webhooks

NCM sends HTTP POST requests to your configured webhook URL when order status changes occur. This SDK provides typed parsing via $client->webhooks->parse(), User-Agent validation via $client->webhooks->isValidUserAgent(), and an event dispatcher for clean webhook handling.

Event Dispatcher

Use the EventDispatcher to route webhook events to handler classes instead of if/else chains:

use OmniCargo\NepalCan\Webhooks\EventDispatcher;
use OmniCargo\NepalCan\Webhooks\WebhookEvent;
use OmniCargo\NepalCan\Webhooks\WebhookHandlerInterface;
use OmniCargo\NepalCan\Resources\Webhook;

// Create a handler
class DeliveryCompletedHandler implements WebhookHandlerInterface
{
    public function handle(Webhook $webhook): void
    {
        // Update order status in your system
    }
}

// Register handlers and dispatch
$dispatcher = new EventDispatcher();
$dispatcher
    ->subscribe(WebhookEvent::DELIVERY_COMPLETED, new DeliveryCompletedHandler())
    ->subscribe(WebhookEvent::ORDER_DISPATCHED, new OrderDispatchedHandler());

$webhook = $client->webhooks->parse($payload);
$dispatcher->dispatch($webhook);

Laravel

For Laravel applications, use the official Laravel wrapper which provides service provider, facade, config publishing, and artisan commands out of the box:

pralhadstha/nepalcan-laravel - Official Laravel wrapper for Nepal Can Move SDK

composer require pralhadstha/nepalcan-laravel

If you prefer using the SDK directly without the Laravel wrapper, you can still use this package in any PHP application including Laravel.

Supported webhook events:

  • WebhookEvent::PICKUP_COMPLETED - Order picked up
  • WebhookEvent::SENT_FOR_DELIVERY - Order sent for delivery
  • WebhookEvent::ORDER_DISPATCHED - Order dispatched from origin branch
  • WebhookEvent::ORDER_ARRIVED - Order arrived at destination branch
  • WebhookEvent::DELIVERY_COMPLETED - Order delivered

Idempotency

NCM may send duplicate webhook notifications. Your application should handle this by tracking processed webhooks to avoid processing the same event twice:

class DeliveryCompletedHandler implements WebhookHandlerInterface
{
    public function handle(Webhook $webhook): void
    {
        // Create a unique key from the webhook data
        $idempotencyKey = $webhook->orderId . ':' . $webhook->event . ':' . $webhook->timestamp;

        // Skip if already processed
        if (ProcessedWebhook::where('idempotency_key', $idempotencyKey)->exists()) {
            return;
        }

        // Process the webhook
        Order::where('ncm_order_id', $webhook->orderId)
            ->update(['status' => $webhook->status]);

        // Mark as processed
        ProcessedWebhook::create(['idempotency_key' => $idempotencyKey]);
    }
}

Error Handling

use OmniCargo\NepalCan\Exceptions\ApiException;
use OmniCargo\NepalCan\Exceptions\AuthenticationException;
use OmniCargo\NepalCan\Exceptions\ValidationException;
use OmniCargo\NepalCan\Exceptions\NotFoundException;

try {
    $order = $client->shipments->find(99999);
} catch (AuthenticationException $e) {
    // Invalid or missing API token (401)
} catch (ValidationException $e) {
    // Invalid parameters (400)
    $errors = $e->getErrors();
} catch (NotFoundException $e) {
    // Order not found (404)
} catch (ApiException $e) {
    // Other API errors
    $statusCode = $e->getStatusCode();
    $errorBody = $e->getErrorBody();
}

API Limits

  • Order Creation: 1,000 per day
  • Order View (Detail, Comments, Status): 20,000 per day

Testing

Run the test suite:

vendor/bin/phpunit

Code Style

This project follows PSR-12 coding standards enforced via PHP-CS-Fixer.

# Check for style violations
composer cs-check

# Auto-fix style violations
composer cs-fix

Changelog

Please see CHANGELOG for more information on what has changed recently.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Credits

License

The MIT License (MIT). Please see LICENSE file for more information.

About

Nepal Can Move (NCM) PHP SDK: A powerful framework‑agnostic PHP library for managing shipments, tracking orders, calculating delivery rates, handling COD, and receiving webhook events for Nepal Can Move logistics.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages