diff --git a/.distignore b/.distignore
new file mode 100644
index 0000000000000000000000000000000000000000..e06a04781c032573c660a3a26a7c9f47fd8bff93
--- /dev/null
+++ b/.distignore
@@ -0,0 +1,12 @@
+*.pdf
+node_modules
+.git
+package.json
+.husky
+package-lock.json
+.distignore
+make-zip.sh
+update-version.js
+.gitlab-ci.yml
+.gitignore
+package
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..6450684a14697f89950e7eadd9aaa21fbd8369ff
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+node_modules
+*.zip
+.idea
+/.idea/
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index de5cdd5e509b31e9302f902adec4fb53deba29ed..bc49012c4a4845e2dab9257ac8c1ce1be67dd98b 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -4,24 +4,20 @@ variables:
   GIT_SUBMODULE_STRATEGY: recursive
 
 stages:
-  - tagged_release
+  - deploy
 
-tagged_deploy:
-  stage: tagged_release
-  only:
-    - tags
+deploy:
+  stage: deploy
   before_script:
-    # - AWS_ACCESS_KEY_ID_KEY=$(echo "$AWS_ACCESS_KEY_ID")
-    # - AWS_SECRET_ACCESS_KEY_KEY=$(echo "$AWS_SECRET_ACCESS_KEY")
-    # - AWS_ACCESS_KEY_ID=$(eval echo -e "\$$AWS_ACCESS_KEY_ID_KEY")
-    # - AWS_SECRET_ACCESS_KEY=$(eval echo -e "\$$AWS_SECRET_ACCESS_KEY_KEY")
-    # - export AWS_ACCESS_KEY_ID
-    # - export AWS_SECRET_ACCESS_KEY
+    - AWS_ACCESS_KEY_ID_KEY=$(echo "$CI_COMMIT_BRANCH"_"AWS_ACCESS_KEY_ID")
+    - AWS_ACCESS_KEY_ID=$(eval echo -e "\$$AWS_ACCESS_KEY_ID_KEY")
+    - AWS_SECRET_ACCESS_KEY_KEY=$(echo "$CI_COMMIT_BRANCH"_"AWS_SECRET_ACCESS_KEY")
+    - AWS_SECRET_ACCESS_KEY=$(eval echo -e "\$$AWS_SECRET_ACCESS_KEY_KEY")
+    - export AWS_ACCESS_KEY_ID
+    - export AWS_SECRET_ACCESS_KEY
   script:
-    # - echo $AWS_ACCESS_KEY_ID
-    # - echo $AWS_SECRET_ACCESS_KEY
-    - wget https://gitlab.bob.co.za/bob-public-utils/bobgo-magento-extension/-/archive/"$CI_COMMIT_TAG"/bobgo-magento-extension-"$CI_COMMIT_TAG".tar.gz
-    - ls -al
-    - aws s3 cp bobgo-magento-extension-"$CI_COMMIT_TAG".tar.gz s3://bobgo-s3-magento-plugin/ --region=af-south-1
-  allow_failure: false
-  when: on_success
\ No newline at end of file
+    - ./make-zip.sh
+    - aws s3 cp bobgo-magento-plugin.zip s3://bobgo-s3-magento-plugin/ --region=af-south-1
+  rules:
+    - if: '$CI_COMMIT_BRANCH == "dev" && $CI_COMMIT_TAG == null'
+      when: always
diff --git a/.husky/pre-commit b/.husky/pre-commit
new file mode 100755
index 0000000000000000000000000000000000000000..0e8cbb02c99d4ef73e87ef96554f3c0f4e3db95f
--- /dev/null
+++ b/.husky/pre-commit
@@ -0,0 +1 @@
+npm config set git-tag-version false && npm version patch && npm run update-version-files && git add package.json etc/module.xml composer.json
diff --git a/Block/TrackOrderLink.php b/Block/TrackOrderLink.php
new file mode 100644
index 0000000000000000000000000000000000000000..ada8c220e6cfa6c217f6caf5ce949885487b5470
--- /dev/null
+++ b/Block/TrackOrderLink.php
@@ -0,0 +1,41 @@
+<?php
+
+namespace BobGroup\BobGo\Block;
+
+use Magento\Framework\View\Element\Html\Link\Current;
+use Magento\Framework\App\Config\ScopeConfigInterface;
+
+class TrackOrderLink extends Current
+{
+    protected $scopeConfig;
+
+    public function __construct(
+        \Magento\Framework\View\Element\Template\Context $context,
+        ScopeConfigInterface $scopeConfig,
+        \Magento\Framework\App\DefaultPathInterface $defaultPath,
+        array $data = []
+    ) {
+        $this->scopeConfig = $scopeConfig;
+        parent::__construct($context, $defaultPath, $data);
+    }
+
+    protected function _toHtml()
+    {
+        // Check if the Track My Order feature is enabled
+        $isEnabled = $this->scopeConfig->isSetFlag(
+            'carriers/bobgo/enable_track_order',
+            \Magento\Store\Model\ScopeInterface::SCOPE_STORE
+        );
+
+        // Return an empty string if the feature is disabled
+        if (!$isEnabled) {
+            return '';
+        }
+
+        // Use the parent class's rendering method
+        return parent::_toHtml();
+    }
+}
+
+
+
diff --git a/Block/TrackingBlock.php b/Block/TrackingBlock.php
new file mode 100644
index 0000000000000000000000000000000000000000..647cb3dbec3f6b0e662c5b75389566ab5e77894e
--- /dev/null
+++ b/Block/TrackingBlock.php
@@ -0,0 +1,26 @@
+<?php
+
+namespace BobGroup\BobGo\Block;
+
+use Magento\Framework\View\Element\Template;
+use Magento\Framework\Registry;
+
+class TrackingBlock extends \Magento\Framework\View\Element\Template
+{
+    protected $registry;
+
+    public function __construct(
+        Template\Context $context,
+        Registry $registry,
+        array $data = []
+    ) {
+        $this->registry = $registry;
+        parent::__construct($context, $data);
+    }
+
+    public function getResponse()
+    {
+        return $this->registry->registry('shipment_data');
+    }
+}
+
diff --git a/Controller/Tracking/Index.php b/Controller/Tracking/Index.php
new file mode 100644
index 0000000000000000000000000000000000000000..78e527f3cf741512ba42d898c378fe839204254a
--- /dev/null
+++ b/Controller/Tracking/Index.php
@@ -0,0 +1,108 @@
+<?php
+namespace BobGroup\BobGo\Controller\Tracking;
+
+use Magento\Framework\App\Action\Context;
+use Magento\Framework\View\Result\PageFactory;
+use Magento\Framework\Registry;
+use Psr\Log\LoggerInterface;
+use Magento\Framework\App\Config\ScopeConfigInterface;
+use Magento\Framework\Controller\Result\RedirectFactory;
+use Magento\Framework\Controller\Result\JsonFactory;
+use Magento\Framework\HTTP\Client\Curl;
+use Magento\Store\Model\StoreManagerInterface;
+use BobGroup\BobGo\Model\Carrier\UData;
+
+class Index extends \Magento\Framework\App\Action\Action
+{
+    protected $resultPageFactory;
+    protected $jsonFactory;
+    protected $curl;
+    protected $logger;
+    protected $scopeConfig;
+    protected $redirectFactory;
+    protected $registry;
+    protected StoreManagerInterface $storeManager;
+
+    public function __construct(
+        Context $context,
+        PageFactory $resultPageFactory,
+        JsonFactory $jsonFactory,
+        LoggerInterface $logger,
+        ScopeConfigInterface $scopeConfig,
+        RedirectFactory $redirectFactory,
+        StoreManagerInterface $storeManager,
+        Curl $curl,
+        Registry $registry
+    ) {
+        $this->resultPageFactory = $resultPageFactory;
+        $this->jsonFactory = $jsonFactory;
+        $this->logger = $logger;
+        $this->scopeConfig = $scopeConfig;
+        $this->redirectFactory = $redirectFactory;
+        $this->storeManager = $storeManager;
+        $this->curl = $curl;
+        $this->registry = $registry;
+        parent::__construct($context);
+    }
+
+    public function execute()
+    {
+        // This is only an extra check after the TrackOrderLink block
+        // Check if the "Track My Order" feature is enabled
+        $isEnabled = $this->scopeConfig->isSetFlag(
+            'carriers/bobgo/enable_track_order',
+            \Magento\Store\Model\ScopeInterface::SCOPE_STORE
+        );
+
+        if (!$isEnabled) {
+            // If the feature is disabled, redirect to home page or show a 404 error
+            return $this->redirectFactory->create()->setPath('noroute');
+        }
+
+        $trackingReference = $this->getRequest()->getParam('order_reference');
+
+        $channel = $this->getStoreUrl();
+
+        if ($trackingReference) {
+            $trackingUrl = sprintf(UData::TRACKING, $channel, $trackingReference);
+                $this->curl->get($trackingUrl);
+                $response = $this->curl->getBody();
+
+                $decodedResponse = json_decode($response, true);
+
+                if (is_array($decodedResponse) && isset($decodedResponse[0])) {
+                    $shipmentData = $decodedResponse[0];
+
+                    // Save data to the registry
+                    $this->registry->register('shipment_data', $shipmentData);
+
+                } else {
+                    // Return early the response is not valid
+                    return $this->resultPageFactory->create();
+                }
+        }
+
+        return $this->resultPageFactory->create();
+    }
+
+    private function getStoreUrl(): string
+    {
+        $url = $this->storeManager->getStore()->getBaseUrl();
+
+        // Remove protocol (http:// or https://)
+        $host = preg_replace('#^https?://#', '', $url);
+
+        // Ensure $host is a string before using it in explode
+        $host = $host ?? '';
+
+        // Remove everything after the host (e.g., paths, query strings)
+        $host = explode('/', $host)[0];
+
+        // If the host starts with 'www.', remove it
+        if (strpos($host, 'www.') === 0) {
+            $host = substr($host, 4);
+        }
+
+        return $host;
+    }
+}
diff --git a/Installation guide - Bob Go shipping extension for Magento 2.pdf b/Installation guide - Bob Go shipping extension for Magento 2.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..2b410bed7e7f035526b31166ae6838292cd7d39b
Binary files /dev/null and b/Installation guide - Bob Go shipping extension for Magento 2.pdf differ
diff --git a/Model/Carrier/BobGo.php b/Model/Carrier/BobGo.php
index 386e4cbc07cd86549a73eaed2cfa25fa22a35185..12e46e69ab6fe302edc536fd7bf791d7ecf49fea 100644
--- a/Model/Carrier/BobGo.php
+++ b/Model/Carrier/BobGo.php
@@ -527,141 +527,6 @@ class BobGo extends AbstractCarrierOnline implements \Magento\Shipping\Model\Car
         }
     }
 
-    /**
-     * Get tracking
-     *
-     * @param string|string[] $trackings
-     * @return \Magento\Shipping\Model\Tracking\Result|null
-     */
-    public function getTracking($trackings)
-    {
-        $this->setTrackingRequest(); // Ensure this method is correctly defined
-
-        if (!is_array($trackings)) {
-            $trackings = [$trackings];
-        }
-
-        foreach ($trackings as $tracking) {
-            $this->_getXMLTracking([$tracking]); // Ensure _getXMLTracking processes tracking correctly
-        }
-
-        return $this->_result; // Ensure _result is a \Magento\Shipping\Model\Tracking\Result
-    }
-
-    /**
-     * Set tracking request
-     *
-     * @return void
-     */
-    protected function setTrackingRequest()
-    {
-        $r = new \Magento\Framework\DataObject();
-
-        $account = $this->getConfigData('account');
-        $r->setData('account', $account); // Using setData with the key 'account'
-
-        $this->_rawTrackingRequest = $r;
-    }
-
-    /**
-     * Get tracking request
-     *
-     * @return \Magento\Framework\DataObject|null
-     */
-    protected function getTrackingRequest(): ?\Magento\Framework\DataObject
-    {
-        return $this->_rawTrackingRequest;
-    }
-
-    /**
-     * Send request for tracking
-     *
-     * @param string[] $tracking
-     * @return void
-     */
-    protected function _getXMLTracking($tracking)
-    {
-        $this->_parseTrackingResponse($tracking);
-    }
-
-    /**
-     * Parse tracking response
-     *
-     * @param string|array<int,string> $trackingValue
-     * @return void
-     */
-    protected function _parseTrackingResponse($trackingValue)
-    {
-        $result = $this->getResult();
-        $carrierTitle = $this->getConfigData('title');
-        $counter = 0;
-
-        if (!is_array($trackingValue)) {
-            $trackingValue = [$trackingValue];
-        }
-
-        foreach ($trackingValue as $trackingReference) {
-            $tracking = $this->_trackStatusFactory->create();
-
-            $tracking->setCarrier(self::CODE);
-            $tracking->setCarrierTitle($carrierTitle);
-
-            // Adjust as needed based on the environment
-            $tracking->setUrl(UData::TRACKING . $trackingReference);
-            $tracking->setTracking($trackingReference);
-            $tracking->addData($this->processTrackingDetails($trackingReference));
-
-            if ($result) {
-                $result->append($tracking);
-                $counter++;
-            }
-        }
-
-        // Tracking Details Not Available
-        if ($counter === 0) {
-            $this->appendTrackingError(
-                $trackingValue[0] ?? '',
-                (string)__('For some reason we can\'t retrieve tracking info right now.')
-            );
-        }
-    }
-
-    /**
-     * Get tracking response
-     *
-     * @return string
-     */
-    public function getResponse(): string
-    {
-        $statuses = '';
-
-        // If $_result is of type \Magento\Shipping\Model\Tracking\Result, handle it
-        if ($this->_result instanceof \Magento\Shipping\Model\Tracking\Result) {
-            if ($trackings = $this->_result->getAllTrackings()) {
-                foreach ($trackings as $tracking) {
-                    if ($data = $tracking->getAllData()) {
-                        if (!empty($data['status'])) {
-                            $statuses .= __($data['status']) . "\n<br/>";
-                        } else {
-                            $statuses .= __('Empty response') . "\n<br/>";
-                        }
-                    }
-                }
-            }
-        }
-
-//        // Handle \Magento\Shipping\Model\Rate\Result if needed
-//        if ($this->_result instanceof \Magento\Shipping\Model\Rate\Result) {
-//            // Implement the logic for Rate\Result if applicable
-//        }
-
-        if (trim($statuses) === '') {
-            $statuses = (string)__('Empty response');
-        }
-
-        return $statuses;
-    }
-
     /**
      * Get allowed shipping methods
      *
@@ -670,7 +535,7 @@ class BobGo extends AbstractCarrierOnline implements \Magento\Shipping\Model\Car
     public function getAllowedMethods(): array
     {
         $allowedMethods = $this->getConfigData('allowed_methods');
-        if ($allowedMethods === false) {
+        if (empty($allowedMethods)) {
             return []; // Return an empty array if no allowed methods are configured
         }
 
@@ -773,55 +638,6 @@ class BobGo extends AbstractCarrierOnline implements \Magento\Shipping\Model\Car
         return $data;
     }
 
-    /**
-     * Parse track details response from Bob Go.
-     *
-     * @param string $trackInfo
-     * @return array<string, array<int, array<string, string>>>
-     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
-     * @SuppressWarnings(PHPMD.NPathComplexity)
-     */
-    private function processTrackingDetails(string $trackInfo): array
-    {
-        $result = [
-            'shippeddate' => [],  // Initializing as an array of arrays
-            'deliverydate' => [], // Initializing as an array of arrays
-            'deliverytime' => [], // Initializing as an array of arrays
-            'deliverylocation' => [], // Initializing as an array of arrays
-            'weight' => [], // Initializing as an array of arrays
-            'progressdetail' => [],  // This will be populated with an array of arrays
-        ];
-
-        $result = $this->_requestTracking($trackInfo, $result);
-
-        return $result;
-    }
-
-    /**
-     * Append error message to rate result instance.
-     *
-     * @param string $trackingValue
-     * @param string $errorMessage
-     * @return void
-     */
-    private function appendTrackingError(string $trackingValue, string $errorMessage): void
-    {
-        $error = $this->_trackErrorFactory->create();
-        $error->setCarrier(self::CODE);
-        $error->setCarrierTitle($this->getConfigData('title'));
-        $error->setTracking($trackingValue);
-        $error->setErrorMessage($errorMessage);
-
-        $result = $this->getResult();
-
-        if ($result !== null) {
-            $result->append($error);
-        } else {
-            // Handle the case where $result is null, such as logging an error
-            $this->_logger->error('Failed to append tracking error: Result object is null.');
-        }
-    }
-
     /**
      * Format a date to 'd M Y'.
      *
@@ -864,6 +680,11 @@ class BobGo extends AbstractCarrierOnline implements \Magento\Shipping\Model\Car
         return UData::RATES_ENDPOINT;
     }
 
+    private function getWebhookUrl(): string
+    {
+        return UData::WEBHOOK_URL;
+    }
+
     /**
      * Perform API Request to Bob Go API and return response.
      *
@@ -883,26 +704,6 @@ class BobGo extends AbstractCarrierOnline implements \Magento\Shipping\Model\Car
         }
     }
 
-    /**
-     * Perform API Request for Shipment Tracking to Bob Go API and return response.
-     *
-     * @param string $trackInfo The tracking information or tracking ID.
-     * @param array<string,array<int,array<string,string>>> $result The result array to be
-     * populated with tracking details.
-     * @return array<string, array<int, array<string, string>>> The updated result array with tracking details.
-     */
-    private function _requestTracking(string $trackInfo, array $result): array
-    {
-        $response = $this->trackBobGoShipment($trackInfo);
-
-        // Validate that the response is an array and contains at least one element
-        if (is_array($response) && isset($response[0]) && is_array($response[0])) {
-            $result = $this->prepareActivity($response[0], $result);
-        }
-
-        return $result;
-    }
-
     /**
      * Format rates from Bob Go API response and append to rate result instance of carrier.
      *
@@ -976,35 +777,6 @@ class BobGo extends AbstractCarrierOnline implements \Magento\Shipping\Model\Car
         }
     }
 
-    /**
-     * Prepare received checkpoints and activity from Bob Go Shipment Tracking API.
-     *
-     * @param array<string,mixed> $response The API response containing tracking checkpoints.
-     * @param array<string,array<int,array<string,string>>> $result The result array to be
-     * populated with activity details.
-     * @return array<string, array<int, array<string, string>>> The updated result array with activity details.
-     */
-    private function prepareActivity(array $response, array $result): array
-    {
-        if (isset($response['checkpoints']) && is_array($response['checkpoints'])) {
-            foreach ($response['checkpoints'] as $checkpoint) {
-                if (is_array($checkpoint) &&
-                    isset($checkpoint['status'], $checkpoint['time']) &&
-                    is_string($checkpoint['status']) &&
-                    is_string($checkpoint['time'])
-                ) {
-                    $result['progressdetail'][] = [
-                        'activity' => $checkpoint['status'],
-                        'deliverydate' => $this->formatDate($checkpoint['time']),
-                        'deliverytime' => $this->formatTime($checkpoint['time']),
-                    ];
-                }
-            }
-        }
-
-        return $result;
-    }
-
     /**
      * Get Working Days between time of checkout and delivery date (min and max).
      *
@@ -1037,21 +809,6 @@ class BobGo extends AbstractCarrierOnline implements \Magento\Shipping\Model\Car
         return $no_days - $weekends;
     }
 
-    /**
-     * Curl request to Bob Go Shipment Tracking API.
-     *
-     * @param string $trackInfo The tracking information or tracking ID.
-     * @return mixed The decoded API response.
-     */
-    private function trackBobGoShipment(string $trackInfo): mixed
-    {
-        $this->curl->get(UData::TRACKING . $trackInfo);
-
-        $response = $this->curl->getBody();
-
-        return json_decode($response, true);
-    }
-
     /**
      * Build the payload for Bob Go API request and return the response.
      *
@@ -1199,27 +956,6 @@ class BobGo extends AbstractCarrierOnline implements \Magento\Shipping\Model\Car
         return $itemsArray;
     }
 
-    /**
-     * Checks if the required data fields are present in the request.
-     *
-     * @param \Magento\Framework\DataObject $request The data object containing the request information.
-     * @return bool True if all required fields are present, otherwise false.
-     */
-    public function hasRequiredData(\Magento\Framework\DataObject $request): bool
-    {
-        $requiredFields = [
-            'dest_country_id',
-            'dest_region_id',
-        ];
-
-        foreach ($requiredFields as $field) {
-            if (!$request->getData($field)) {
-                return false;
-            }
-        }
-        return true;
-    }
-
     /**
      * Trigger a test for rates.
      *
@@ -1310,4 +1046,72 @@ class BobGo extends AbstractCarrierOnline implements \Magento\Shipping\Model\Car
         }
         return false;
     }
+
+    public function isWebhookEnabled(): bool
+    {
+        $enabled = $this->scopeConfig->getValue(
+            'carriers/bobgo/enable_webhooks',
+            \Magento\Store\Model\ScopeInterface::SCOPE_STORE
+        );
+
+        // Cast the value to a boolean
+        return filter_var($enabled, FILTER_VALIDATE_BOOLEAN);
+    }
+
+
+    public function triggerWebhookTest(): bool
+    {
+        $webhookKey = $this->scopeConfig->getValue(
+            'carriers/bobgo/webhook_key',
+            \Magento\Store\Model\ScopeInterface::SCOPE_STORE
+        );
+
+        // Check if the webhook key is empty and return false
+        if (empty($webhookKey)) {
+            return false;
+        }
+
+        // Convert the string to a boolean value
+        $isEnabled = $this->isWebhookEnabled();
+
+        $storeId = strval($this->_storeManager->getStore()->getId());
+
+        $payload = [
+            'event' => 'webhook_validation',
+            'channel_identifier' => $this->getBaseUrl(),
+            'store_id' => $storeId,
+            'webhooks_enabled' => $isEnabled,
+        ];
+
+        try {
+            $this->encodeWebhookAndPostRequest($this->getWebhookUrl(), $payload, $storeId, $webhookKey);
+            $statusCode = $this->curl->getStatus();
+            $responseBody = $this->curl->getBody();
+
+            if ($statusCode != 200) {
+                throw new LocalizedException(__('Status code from BobGo: %1', $statusCode));
+            }
+        } catch (\Exception $e) {
+            return false;
+        }
+        return true;
+    }
+
+    public function encodeWebhookAndPostRequest($url, $data, $storeId, $webhookKey) {
+        // Generate the HMAC-SHA256 hash as raw binary data
+        $rawSignature = hash_hmac('sha256', $storeId, $webhookKey, true);
+        // Encode the binary data in Base64
+        $signature = base64_encode($rawSignature);
+        // Set headers and post the data
+        $this->curl->addHeader('Content-Type', 'application/json');
+        $this->curl->addHeader('x-m-webhook-signature', $signature);
+
+        $payloadJson = json_encode($data);
+        if ($payloadJson === false) {
+            throw new \RuntimeException('Failed to encode payload to JSON.');
+        }
+
+        $this->curl->addHeader('Content-Type', 'application/json');
+        $this->curl->post($url, $payloadJson);
+    }
 }
diff --git a/Model/Carrier/UData.php b/Model/Carrier/UData.php
index 47b5d8b050f519a4e96f2ae432f3a0ea6ab70e0d..bbb17ddfbad6bffbb33cd3baab5e139ab6581cb4 100644
--- a/Model/Carrier/UData.php
+++ b/Model/Carrier/UData.php
@@ -20,4 +20,11 @@ class UData
      * @var string
      */
     public const RATES_ENDPOINT = 'https://api.bobgo.co.za/rates-at-checkout/magento';
+
+    /**
+     * Order create/update webhook URL
+     *
+     * @var string
+     */
+    public const WEBHOOK_URL = 'https://api.bobgo.co.za/webhook/channel/magento';
 }
diff --git a/Observer/ConfigChangeObserver.php b/Observer/ConfigChangeObserver.php
index 1b6c07214501db7cd9ba19dc325fe3bbade643a5..efc0179a7bd1288e9f61931fae30f25f63597569 100644
--- a/Observer/ConfigChangeObserver.php
+++ b/Observer/ConfigChangeObserver.php
@@ -52,6 +52,7 @@ class ConfigChangeObserver implements ObserverInterface
     {
         $changedPaths = $observer->getEvent()->getData('changed_paths');
 
+        // Test for rates at checkout
         if (is_array($changedPaths) && in_array('carriers/bobgo/active', $changedPaths)) {
             if ($this->bobGo->isActive()) {
                 $result = $this->bobGo->triggerRatesTest();
@@ -70,5 +71,23 @@ class ConfigChangeObserver implements ObserverInterface
                 }
             }
         }
+
+        // Test for webhooks
+        if ((is_array($changedPaths) && in_array('carriers/bobgo/enable_webhooks', $changedPaths)) || (is_array($changedPaths) && in_array('carriers/bobgo/webhook_key', $changedPaths))) {
+            $result = $this->bobGo->triggerWebhookTest();
+
+            if ($this->bobGo->isWebhookEnabled()) {
+                if ($result) {
+                    $this->messageManager->addSuccessMessage(
+                        __('Webhook validation successful.')
+                    );
+                } else {
+                    $this->messageManager->addErrorMessage(
+                        __('Webhook validation failed. Please check your internet connection
+                        and use your Bob Go integration consumer secret key for webhook validation.')
+                    );
+                }
+            }
+        }
     }
 }
diff --git a/Observer/ModifyShippingDescription.php b/Observer/ModifyShippingDescription.php
new file mode 100644
index 0000000000000000000000000000000000000000..2e443aff7dc7af482ec5ae4630129244e080b95c
--- /dev/null
+++ b/Observer/ModifyShippingDescription.php
@@ -0,0 +1,58 @@
+<?php
+
+namespace BobGroup\BobGo\Observer;
+
+use Magento\Framework\Event\ObserverInterface;
+use Magento\Framework\Event\Observer;
+use Psr\Log\LoggerInterface;
+
+class ModifyShippingDescription implements ObserverInterface
+{
+    public const CODE = 'bobgo';
+
+    protected $logger;
+
+    public function __construct(LoggerInterface $logger)
+    {
+        $this->logger = $logger;
+    }
+
+    public function execute(Observer $observer)
+    {
+        // Get the order object from the event
+        $order = $observer->getEvent()->getOrder();
+
+        // Get the current shipping description
+        $shippingDescription = $order->getShippingDescription();
+
+        // Get the method title from the shipping description
+        $methodTitle = $this->extractMethodTitle($shippingDescription);
+
+        // Set the new shipping description based only on MethodTitle
+        $newDescription = $methodTitle;
+
+        // Update the shipping description in the order
+        $order->setShippingDescription($newDescription);
+    }
+
+    /**
+     * Helper function to extract the method title from the original shipping description
+     *
+     * @param string $shippingDescription
+     * @return string
+     */
+    private function extractMethodTitle($shippingDescription)
+    {
+        // Find the position of the last dash in the string
+        $lastDashPosition = strrpos($shippingDescription, ' - ');
+
+        // If a dash is found, extract the part after the last dash
+        if ($lastDashPosition !== false) {
+            return trim(substr($shippingDescription, $lastDashPosition + 3)); // +3 to skip the ' - ' part
+        }
+
+        // If no dash is found, return the full description (fallback)
+        return $shippingDescription;
+    }
+
+}
diff --git a/Observer/OrderCreateWebhook.php b/Observer/OrderCreateWebhook.php
new file mode 100644
index 0000000000000000000000000000000000000000..74f1ce4520155ee9b072cd2b6d0d2c6e00ea89a8
--- /dev/null
+++ b/Observer/OrderCreateWebhook.php
@@ -0,0 +1,19 @@
+<?php
+
+namespace BobGroup\BobGo\Observer;
+
+use Magento\Framework\Event\Observer;
+
+class OrderCreateWebhook extends OrderWebhookBase
+{
+    public function execute(Observer $observer)
+    {
+        $order = $observer->getEvent()->getOrder();
+        if (!$order) {
+            return;
+        }
+
+        // Extract order data and send to the webhook URL
+        $this->sendWebhook($order);
+    }
+}
diff --git a/Observer/OrderWebhookBase.php b/Observer/OrderWebhookBase.php
new file mode 100644
index 0000000000000000000000000000000000000000..311daa7b64f0d512d79bf94f2e6af3f894a3deac
--- /dev/null
+++ b/Observer/OrderWebhookBase.php
@@ -0,0 +1,74 @@
+<?php
+
+namespace BobGroup\BobGo\Observer;
+
+use BobGroup\BobGo\Model\Carrier\UData;
+use Magento\Framework\App\Config\ScopeConfigInterface;
+use Magento\Framework\Event\ObserverInterface;
+use Magento\Framework\HTTP\Client\Curl;
+use Magento\Store\Model\StoreManagerInterface;
+use Psr\Log\LoggerInterface;
+use BobGroup\BobGo\Model\Carrier\BobGo;
+
+abstract class OrderWebhookBase implements ObserverInterface
+{
+    protected Curl $curl;
+    protected LoggerInterface $logger;
+    protected StoreManagerInterface $storeManager;
+    protected ScopeConfigInterface $scopeConfig;
+    protected $bobGo;
+
+    public function __construct(LoggerInterface $logger, Curl $curl, StoreManagerInterface $storeManager, ScopeConfigInterface $scopeConfig, BobGo $bobGo)
+    {
+        $this->logger = $logger;
+        $this->curl = $curl;
+        $this->storeManager = $storeManager;
+        $this->scopeConfig = $scopeConfig;
+        $this->bobGo = $bobGo;
+    }
+
+    protected function sendWebhook($order)
+    {
+        // Return early if not enabled
+        if (!$this->bobGo->isWebhookEnabled()) {
+            return;
+        }
+
+        // Webhook URL
+        $url = $this->getWebhookUrl();
+
+        $storeId = $this->getStoreId();
+
+        $orderId = $order->getId();
+
+        // Prepare payload
+        $data = [
+            'event' => 'order_updated',
+            'order_id' => $orderId,
+            'channel_identifier' => $this->bobGo->getBaseUrl(),
+            'store_id' => $storeId,
+            'webhooks_enabled' => true, // If we get to this point webhooks are enabled
+        ];
+
+        // Generate the signature using the webhook key saved in config
+        $webhookKey = $this->scopeConfig->getValue('carriers/bobgo/webhook_key', \Magento\Store\Model\ScopeInterface::SCOPE_STORE);
+        // Check if the webhook key is empty and return false
+        if (empty($webhookKey)) {
+            return;
+        }
+
+        // Send the webhook
+        $this->bobGo->encodeWebhookAndPostRequest($url, $data, $storeId, $webhookKey);
+    }
+
+    private function getWebhookUrl(): string
+    {
+        return UData::WEBHOOK_URL;
+    }
+
+    private function getStoreId(): string
+    {
+        $storeId = $this->storeManager->getStore()->getId();
+        return $storeId;
+    }
+}
diff --git a/Plugin/Block/DataProviders/Tracking/ChangeTitle.php b/Plugin/Block/DataProviders/Tracking/ChangeTitle.php
deleted file mode 100644
index a035d238ef81b90a649f0b7ae33541f6b7c6e7ee..0000000000000000000000000000000000000000
--- a/Plugin/Block/DataProviders/Tracking/ChangeTitle.php
+++ /dev/null
@@ -1,31 +0,0 @@
-<?php
-
-namespace BobGroup\BobGo\Plugin\Block\DataProviders\Tracking;
-
-use BobGroup\BobGo\Model\Carrier;
-use Magento\Shipping\Model\Tracking\Result\Status;
-use Magento\Shipping\Block\DataProviders\Tracking\DeliveryDateTitle as Subject;
-
-/**
- * Plugin to change delivery date title with bobgo customized value
- */
-
-class ChangeTitle
-{
-    /**
-     * Title modification in case if bobgo used as carrier
-     *
-     * @param Subject $subject
-     * @param \Magento\Framework\Phrase|string $result
-     * @param Status $trackingStatus
-     * @return \Magento\Framework\Phrase|string
-     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
-     */
-    public function afterGetTitle(Subject $subject, $result, Status $trackingStatus)
-    {
-        if ($trackingStatus->getCarrier() === \BobGroup\BobGo\Model\Carrier\BobGo::CODE) {
-            $result = __('Expected delivery:');
-        }
-        return $result;
-    }
-}
diff --git a/Plugin/Block/Tracking/PopUpDeliveryDate.php b/Plugin/Block/Tracking/PopUpDeliveryDate.php
deleted file mode 100644
index bb375285de7c84f6104c1b4014689803c4e9365f..0000000000000000000000000000000000000000
--- a/Plugin/Block/Tracking/PopUpDeliveryDate.php
+++ /dev/null
@@ -1,53 +0,0 @@
-<?php
-
-namespace BobGroup\BobGo\Plugin\Block\Tracking;
-
-use Magento\Shipping\Block\Tracking\Popup;
-use Magento\Shipping\Model\Tracking\Result\Status;
-
-/*
- * Plugin to update delivery date value in case if Bob Go is a carrier used
- */
-class PopupDeliveryDate
-{
-    /**
-     * Bob Go carrier code
-     */
-    private const BOB_GO_CARRIER_CODE = 'bobgo_carrier_code'; // Replace with your actual carrier code
-
-    /**
-     * Show only date for expected delivery in case if Bob Go is a carrier
-     *
-     * @param Popup $subject
-     * @param string $result
-     * @param string $date
-     * @param string $time
-     * @return string
-     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
-     */
-    public function afterFormatDeliveryDateTime(Popup $subject, $result, $date, $time)
-    {
-        if ($this->getCarrier($subject) === self::BOB_GO_CARRIER_CODE) {
-            $result = $subject->formatDeliveryDate($date);
-        }
-        return $result;
-    }
-
-    /**
-     * Retrieve carrier name from tracking info
-     *
-     * @param Popup $subject
-     * @return string
-     */
-    private function getCarrier(Popup $subject): string
-    {
-        foreach ($subject->getTrackingInfo() as $trackingData) {
-            foreach ($trackingData as $trackingInfo) {
-                if ($trackingInfo instanceof Status) {
-                    return $trackingInfo->getCarrier() ?? '';
-                }
-            }
-        }
-        return '';
-    }
-}
diff --git a/Readme.md b/Readme.md
index fcb6fb88a897b0fe65141ac458fc1de46b5f6343..e85f78fa7cbd9a3da16ba3f9a342e2ef2726e4d9 100644
--- a/Readme.md
+++ b/Readme.md
@@ -1,97 +1,3 @@
-# Magento 2 Bob Go Shipping Extension
+# Bob Go shipping extension for Magento 2
 
-## Introduction
-
-A complete guide to install Magento Bob Go Shipping extension in Magento 2. 
-
-## Features
->This extension allows you to get real-time shipping rates from Bob Go shipping services and display them to your customers during checkout.
-
->This extension also allows you to track shipments and get delivery status updates from Bob Go shipping services.
-
-## How to install Magento 2 Bob Go Shipping Extension
-
-### Option 1 (recommended): Install via composer 
-
-Run the following command in Magento 2 root folder:</br>
-
->_Note: You must have composer installed on your server for this option_
-
-#### 1. Execute the following command to install the module:
-
-``` 
-composer require bobgo/bobgo-magento-extension
-```
-#### 2. Enter following commands to enable the module:
-
-```
-bin/magento module:enable BobGroup_BobGo
-bin/magento cache:clean
-bin/magento cache:flush
-bin/magento setup:upgrade
-bin/magento setup:di:compile
-bin/magento setup:static-content:deploy
-```
-
-### Option 2: Install via zip file
-
-1. Download the extension zip file from the link below: </br>
-
-    <a href="https://gitlab.bob.co.za/bob-public-utils/bobgo-magento-extension/-/archive/prod/bobgo-magento-extension-prod.zip"> Download Magento 2 Bob Go Shipping Extension </a>
-
-2. Unzip the file and copy contents
-
-3. Create `BobGroup/BobGo` <em>Directory</em>
-
-**It should look like this:** </br>
->{Magento root}/app/code/BobGroup/BobGo/
-
-
->**{Magento root}**`/app/code/BobGroup/BobGo/`**{Paste here}**
-
-
-4. Go to Magento root folder and run all commands below  to install `BobGroup_BobGo`: </br>
-```
-bin/magento cache:clean
-bin/magento cache:flush
-bin/magento setup:upgrade
-bin/magento setup:di:compile
-bin/magento setup:static-content:deploy
-```
-_____________________________________________________________________________________________________________________
-# After installation
-
-
-## How to configure Magento 2 Bob Go Shipping Extension 
-
-### ✓ Step 1: Create an account on Bob Go
-
-You need to create an account on Bob Go to get your store identified by the API. 
-
-Please visit [Bob Go](https://bobgo.co.za) to create an account.
-
-### ✓ Step 2: Integrate Magento and Bob Go
-
-1. In the Magento admin portal click on `System > Integrations` and click on `Add New Integration`
-2. Under `Basic Settings > Integration Info` fill in the name of the integration eg. Bob Go  
-3. Under `Basic Settings > API` select `All` for Resource access
-4. Click `Save` and enter your Magento admin portal password
-5. The `Integration Details` will be displayed on the page
-6. On [Bob Go](https://bobgo.co.za) go to `Sales channels > Add channel > Magento` and enter the Magento integration details from step 5 and click `Grant access`
-7. On Bob Go go to `Rates at checkout > Settings > Installed channels` and enable your channel for rates at checkout
-8. Make sure you have service levels configured and enabled on Bob Go `Rates at checkout > Service levels`
-
-### ✓ Step 3: Login to Magento Admin
-
-1. In the Magento admin portal click on `Stores > Configuration > Sales > Delivery Methods` 
-2. Go to the Bob Go delivery method and enable Bob Go rates at checkout
-3.  Click `Save Config`
-4. A message at the top of the screen will confirm that rates at checkout is enabled correctly: `Bob Go rates at checkout connected.`
-
-#### Admin Configurations: Update Store Information*
-
-When the extension is **installed** and **enabled**, a new field will be created in `Store Information` : `Suburb`. Enter the necessary details:
-
-1. `Stores`> `Configuration`> `General`>`General`
-2. `Store Information`>`Suburb`
-3. Update the store information and click `Save config`
+See the installation guide for information: [Installation Guide](./Installation guide - Bob Go shipping extension for Magento 2.pdf)
\ No newline at end of file
diff --git a/Test/Unit/Plugin/Block/DataProviders/Tracking/ChangeTitleTest.php b/Test/Unit/Plugin/Block/DataProviders/Tracking/ChangeTitleTest.php
deleted file mode 100644
index 4d8bd9d0a66447160396590cc4b878cb8acfad25..0000000000000000000000000000000000000000
--- a/Test/Unit/Plugin/Block/DataProviders/Tracking/ChangeTitleTest.php
+++ /dev/null
@@ -1,62 +0,0 @@
-<?php
-
-namespace BobGroup\BobGo\Test\Unit\Plugin\Block\DataProviders\Tracking;
-
-use BobGroup\BobGo\Plugin\Block\DataProviders\Tracking\ChangeTitle;
-use BobGroup\BobGo\Model\Carrier\BobGo;
-use Magento\Shipping\Model\Tracking\Result\Status;
-use Magento\Shipping\Block\DataProviders\Tracking\DeliveryDateTitle as Subject;
-use PHPUnit\Framework\TestCase;
-
-class ChangeTitleTest extends TestCase
-{
-    /**
-     * @var ChangeTitle
-     */
-    private $plugin;
-
-    protected function setUp(): void
-    {
-        // Instantiate the ChangeTitle plugin
-        $this->plugin = new ChangeTitle();
-    }
-
-    public function testAfterGetTitleWithBobGoCarrier(): void
-    {
-        // Create a custom Status object with BobGo carrier
-        $status = $this->getMockBuilder(Status::class)
-            ->setMethods(['getCarrier'])
-            ->getMock();
-
-        $status->method('getCarrier')->willReturn(BobGo::CODE);
-
-        // Mock the Subject class
-        $subjectMock = $this->createMock(Subject::class);
-
-        // Call the plugin method afterGetTitle
-        $result = $this->plugin->afterGetTitle($subjectMock, 'Original Title', $status);
-
-        // Assert that the title was changed for BobGo carrier
-        $this->assertEquals('Expected delivery:', $result);
-    }
-
-    public function testAfterGetTitleWithOtherCarrier(): void
-    {
-        // Create a custom Status object with a different carrier
-        $status = $this->getMockBuilder(Status::class)
-            ->setMethods(['getCarrier'])
-            ->getMock();
-
-        $status->method('getCarrier')->willReturn('other_carrier_code');
-
-        // Mock the Subject class
-        $subjectMock = $this->createMock(Subject::class);
-
-        // Call the plugin method afterGetTitle
-        $originalTitle = 'Original Title';
-        $result = $this->plugin->afterGetTitle($subjectMock, $originalTitle, $status);
-
-        // Assert that the title was not changed for other carriers
-        $this->assertEquals($originalTitle, $result);
-    }
-}
diff --git a/Test/Unit/Plugin/Block/Tracking/PopUpDeliveryDateTest.php b/Test/Unit/Plugin/Block/Tracking/PopUpDeliveryDateTest.php
deleted file mode 100644
index 6c01770254cd04592f5fbafa8bfccacd4d6bfd27..0000000000000000000000000000000000000000
--- a/Test/Unit/Plugin/Block/Tracking/PopUpDeliveryDateTest.php
+++ /dev/null
@@ -1,92 +0,0 @@
-<?php
-
-namespace BobGroup\BobGo\Test\Unit\Plugin\Block\Tracking;
-
-use BobGroup\BobGo\Plugin\Block\Tracking\PopupDeliveryDate;
-use Magento\Shipping\Block\Tracking\Popup;
-use Magento\Shipping\Model\Tracking\Result\Status;
-use PHPUnit\Framework\TestCase;
-
-class PopupDeliveryDateTest extends TestCase
-{
-    /**
-     * @var PopupDeliveryDate
-     */
-    private $plugin;
-
-    protected function setUp(): void
-    {
-        // Instantiate the PopupDeliveryDate plugin
-        $this->plugin = new PopupDeliveryDate();
-    }
-
-    public function testAfterFormatDeliveryDateTimeWithBobGoCarrier(): void
-    {
-        // Create an instance of the Status class
-        $status = new Status();
-        $status->setCarrier('bobgo_carrier_code');
-
-        // Mock the Popup class
-        $popupMock = $this->createMock(Popup::class);
-        $popupMock->method('getTrackingInfo')->willReturn([
-            ['tracking_info' => $status],
-        ]);
-
-        // Mock the formatDeliveryDate method
-        $popupMock->method('formatDeliveryDate')
-            ->with('2024-08-19')
-            ->willReturn('Aug 19, 2024');
-
-        // Call the plugin method afterFormatDeliveryDateTime
-        $result = $this->plugin->afterFormatDeliveryDateTime(
-            $popupMock,
-            'Aug 19, 2024 10:00 AM',
-            '2024-08-19',
-            '10:00 AM'
-        );
-
-        // Assert that the time was stripped for BobGo carrier
-        $this->assertEquals('Aug 19, 2024', $result);
-    }
-
-    public function testAfterFormatDeliveryDateTimeWithOtherCarrier(): void
-    {
-        // Create an instance of the Status class
-        $status = new Status();
-        $status->setCarrier('other_carrier_code');
-
-        // Mock the Popup class
-        $popupMock = $this->createMock(Popup::class);
-        $popupMock->method('getTrackingInfo')->willReturn([
-            ['tracking_info' => $status],
-        ]);
-
-        // Call the plugin method afterFormatDeliveryDateTime
-        $result = $this->plugin->afterFormatDeliveryDateTime(
-            $popupMock,
-            'Aug 19, 2024 10:00 AM',
-            '2024-08-19',
-            '10:00 AM'
-        );
-
-        // Assert that the time remains unchanged for other carriers
-        $this->assertEquals('Aug 19, 2024 10:00 AM', $result);
-    }
-
-    public function testGetCarrierWithNoTrackingInfo(): void
-    {
-        // Mock the Popup class with no tracking info
-        $popupMock = $this->createMock(Popup::class);
-        $popupMock->method('getTrackingInfo')->willReturn([]);
-
-        // Call the getCarrier method directly
-        $reflection = new \ReflectionClass($this->plugin);
-        $method = $reflection->getMethod('getCarrier');
-        $method->setAccessible(true);
-
-        $result = $method->invokeArgs($this->plugin, [$popupMock]);
-
-        // Assert that an empty string is returned when no tracking info is available
-        $this->assertEquals('', $result);
-    }
-}
diff --git a/composer.json b/composer.json
index 637ad878c7781f367b045144816252b0b374fec8..83317accc96cd68c7d9ad9191e5806418670b9e0 100644
--- a/composer.json
+++ b/composer.json
@@ -2,7 +2,7 @@
     "name": "bobgo/bobgo-magento-extension",
     "description": "Smart shipping and order management solution in South Africa",
     "type": "magento2-module",
-    "version": "1.0.33",
+    "version": "1.0.41",
     "authors": [
         {
             "name": "Bob Go",
diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml
index 410c2c2b9a14e1ecfe406f498fb95d51783d9206..03d77876036cd97ffb817ff3211d9a31767af471 100644
--- a/etc/adminhtml/system.xml
+++ b/etc/adminhtml/system.xml
@@ -20,7 +20,7 @@
                 </field>
                 <field id="active" translate="label" type="select" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="0">
                     <label>Enable Bob Go rates at checkout</label>
-                    <comment>When this setting is enabled, your customers will be presented with shipping rates at checkout, as configured on the Bob Go platform under Rates at checkout.</comment>
+                    <comment>When enabled, your customers will be presented with shipping rates at checkout, as configured on the Bob Go platform under Rates at checkout.</comment>
                     <source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
                 </field>
                 <field id="additional_info" translate="label" type="select" sortOrder="7" showInDefault="1" showInWebsite="1">
@@ -28,6 +28,25 @@
                     <source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
                     <comment>Displays the delivery timeframe and additional service level description, as configured on Bob Go.</comment>
                 </field>
+
+                <!-- Enable Webhooks Checkbox -->
+                <field id="enable_webhooks" translate="label" type="select" sortOrder="8" showInDefault="1" showInWebsite="1" showInStore="0">
+                    <label>Enable webhooks</label>
+                    <source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
+                    <comment>When this setting is enabled, webhooks will be sent to Bob Go to notify about order creation and updates, ensuring real-time synchronization between your store and Bob Go.</comment>
+                </field>
+
+                <!-- Webhook Key Input Field -->
+                <field id="webhook_key" translate="label" type="text" sortOrder="9" showInDefault="1" showInWebsite="1" showInStore="0">
+                    <label>Webhook authentication key</label>
+                    <comment>Enter your Bob Go integration API consumer secret key for webhook authentication.</comment>
+                </field>
+<!--                Hiding the `Enable Track My Order` setting for now-->
+                <field id="enable_track_order" translate="label" type="select" sortOrder="10" showInDefault="0" showInWebsite="0" showInStore="0">
+                    <label>Enable Track my order</label>
+                    <comment>When this setting is enabled, your customers will be presented with a page to track orders.</comment>
+                    <source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
+                </field>
             </group>
         </section>
     </system>
diff --git a/etc/events.xml b/etc/events.xml
index bfb5e9669522f329879ecc96da2ca4a571ea8b2e..a6fab5c7c81c3fe6dd4331d91aaa71bd88848158 100644
--- a/etc/events.xml
+++ b/etc/events.xml
@@ -1,3 +1,11 @@
 <?xml version="1.0"?>
 <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
+    <event name="sales_order_save_after">
+        <observer name="order_create_webhook" instance="BobGroup\BobGo\Observer\OrderCreateWebhook"/>
+    </event>
+    <!-- app/code/Vendor/Module/etc/events.xml -->
+    <event name="sales_order_place_before">
+        <observer name="modify_shipping_description" instance="BobGroup\BobGo\Observer\ModifyShippingDescription"/>
+    </event>
+
 </config>
diff --git a/etc/frontend/di.xml b/etc/frontend/di.xml
index bc1aaebb43890432e80d8e9d27bfd5838b7c8e8b..25a80a9bc5c7b63aad2741c99339161717ede977 100644
--- a/etc/frontend/di.xml
+++ b/etc/frontend/di.xml
@@ -13,4 +13,12 @@
             <argument name="logger" xsi:type="object">Psr\Log\LoggerInterface</argument>
         </arguments>
     </type>
+    <type name="BobGroup\BobGo\Observer\OrderCreateWebhook">
+        <arguments>
+            <argument name="logger" xsi:type="object">Psr\Log\LoggerInterface</argument>
+            <argument name="curl" xsi:type="object">Magento\Framework\HTTP\Client\Curl</argument>
+            <argument name="storeManager" xsi:type="object">Magento\Store\Model\StoreManagerInterface</argument>
+        </arguments>
+    </type>
+
 </config>
diff --git a/etc/frontend/routes.xml b/etc/frontend/routes.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d6d10467741f62ea0f0f24d7fba12bc9e921e814
--- /dev/null
+++ b/etc/frontend/routes.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
+    <router id="standard">
+        <route id="bobgo" frontName="bobgo">
+            <module name="BobGroup_BobGo" />
+        </route>
+    </router>
+</config>
diff --git a/etc/module.xml b/etc/module.xml
index fe2b36da4d6bad5e35cb60c85d1f1ff05d245001..a79063f98eb5a146f6f34d8de1fa087c52a2042f 100644
--- a/etc/module.xml
+++ b/etc/module.xml
@@ -7,7 +7,7 @@
  */
 -->
 <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
-    <module name="BobGroup_BobGo" setup_version="1.0.0">
+    <module name="BobGroup_BobGo" setup_version="1.0.41">
         <sequence>
             <module name="Magento_Webapi"/>
             <module name="Magento_Catalog"/>
diff --git a/make-zip.sh b/make-zip.sh
new file mode 100755
index 0000000000000000000000000000000000000000..6385066a926187eb2b6734463bd258256cd2cfe1
--- /dev/null
+++ b/make-zip.sh
@@ -0,0 +1,153 @@
+#!/bin/bash
+
+# Exit immediately if a command exits with a non-zero status
+#
+set -e
+
+# Function to log messages
+log() {
+    echo "** $1"
+}
+
+# Function to install jq if not installed
+install_jq() {
+    if command -v jq >/dev/null 2>&1; then
+        log "jq is already installed."
+    else
+        log "jq is not installed. Attempting to install..."
+
+        if [[ "$OSTYPE" == "darwin"* ]]; then
+            if command -v brew >/dev/null 2>&1; then
+                log "Installing jq using Homebrew..."
+                brew install jq
+            else
+                log "Homebrew is not installed. Please install Homebrew first:"
+                log "https://brew.sh/"
+                exit 1
+            fi
+        elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
+            if command -v apt-get >/dev/null 2>&1; then
+                log "Installing jq using apt-get..."
+                sudo apt-get update
+                sudo apt-get install -y jq
+            else
+                log "apt-get not found. Please install jq manually."
+                exit 1
+            fi
+        else
+            log "Unsupported OS. Please install jq manually."
+            exit 1
+        fi
+
+        if command -v jq >/dev/null 2>&1; then
+            log "jq installed successfully."
+        else
+            log "Failed to install jq. Please install it manually."
+            exit 1
+        fi
+    fi
+}
+
+# Function to ensure Perl is installed
+install_perl() {
+    if command -v perl >/dev/null 2>&1; then
+        log "Perl is already installed."
+    else
+        log "Perl is not installed. Please install Perl to proceed."
+        exit 1
+    fi
+}
+
+# Function to extract version using jq
+get_version() {
+    if command -v jq >/dev/null 2>&1; then
+        jq -r '.version' package.json
+    else
+        # Fallback to grep and awk if jq is not available
+        grep '"version":' package.json | head -1 | awk -F'"' '{print $4}'
+    fi
+}
+
+# Function to update the 'Version:' header in bobpay-plugin.php using Perl
+update_version_header() {
+    local VERSION=$1
+    local FILE="composer.json"
+
+    log "Updating 'version:' header in ${FILE} using Perl..."
+
+    # Use Perl to update the 'Version:' line
+    perl -pi -e "s/(\"version\":\s*\")([0-9.]+)(\"\,)/\${1}${VERSION}\"\,/g" "$FILE"
+    log "'version:' header updated to ${VERSION}."
+}
+
+update_define_constant() {
+    local VERSION=$1
+    local FILE="etc/module.xml"
+
+    log "Updating 'version' constant in ${FILE} using Perl..."
+
+    # Use Perl to replace the version constant
+    perl -pi -e "s/(setup_version=\")([^\"]*)/\${1}${VERSION}/g" "$FILE"
+    log "'setup_version' constant updated to ${VERSION}."
+}
+
+# Function to build the plugin
+build_plugin() {
+    log "Building plugin..."
+    npm install
+    log "Plugin built successfully."
+}
+
+# Function to create the zip package
+create_zip() {
+    local VERSION=$1
+    local ZIPNAME="bobgo-magento-plugin.zip"
+    local PACKAGE_DIR="package"
+
+    log "Creating zip file: ${ZIPNAME}..."
+
+    # Remove any existing package directory and zip file
+    rm -rf "${PACKAGE_DIR}"
+    rm -f "${ZIPNAME}"
+
+    # Create the package directory
+    mkdir -p "${PACKAGE_DIR}"
+
+    # Use rsync to copy files, excluding those in .distignore
+    log "Copying files to package directory..."
+    rsync -av --exclude-from='.distignore' ./ "${PACKAGE_DIR}/"
+
+    # Create the zip file from the package directory
+    log "Creating zip file..."
+    cd "${PACKAGE_DIR}"
+    zip -r "../${ZIPNAME}" .
+    cd ..
+
+    # Clean up the package directory
+    log "Cleaning up..."
+    rm -rf "${PACKAGE_DIR}"
+
+    log "Zip file '${ZIPNAME}' created successfully."
+}
+
+# Main script execution
+main() {
+    log "Starting build process..."
+
+    install_jq
+    install_perl
+
+    VERSION=$(get_version)
+    log "Extracted version: ${VERSION}"
+
+    build_plugin
+    update_version_header "${VERSION}"
+    update_define_constant "${VERSION}"
+    create_zip "${VERSION}"
+
+    log "Build process completed successfully."
+}
+
+# Execute the main function
+main
+
diff --git a/package.json b/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..e44822d7d797846f0186f039f9565bc09c05df2e
--- /dev/null
+++ b/package.json
@@ -0,0 +1,19 @@
+{
+  "name": "bobgo-magento-plugin",
+  "description": "Bob Go magento plugin",
+  "version": "1.0.41",
+  "license": "GPL-2.0-or-later",
+  "scripts": {
+    "prepare": "husky install",
+    "update-version-files": "node update-version.js"
+  },
+  "husky": {
+    "hooks": {
+      "pre-commit": "npm config set git-tag-version false && npm version patch && npm run update-version-files && git add package.json etc/module.xml composer.json && pretty-quick --staged"
+    }
+  },
+  "devDependencies": {
+    "husky": "^8.0.1",
+    "npm-run-all": "^4.1.5"
+  }
+}
diff --git a/update-version.js b/update-version.js
new file mode 100644
index 0000000000000000000000000000000000000000..f5a9606305502bad56e35c586a0f27771e4d1c3c
--- /dev/null
+++ b/update-version.js
@@ -0,0 +1,36 @@
+const fs = require('fs');
+
+// Read version from package.json
+const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8'));
+const version = packageJson.version;
+
+// Files to update
+const filesToUpdate = ['composer.json', 'etc/module.xml'];
+
+// Function to update version in files
+function updateVersionInFile(filePath) {
+  let content = fs.readFileSync(filePath, 'utf8');
+
+  if (filePath === 'composer.json') {
+    // Update the Version header in the plugin file
+    // Update the version in composer.json
+    content = content.replace(
+        /(\"version\":\s*\")([0-9.]+)(\"\,)/g,
+        `$1${version}$3`
+    );
+  }
+
+  if (filePath === 'etc/module.xml') {
+    // Update the version tag in etc/module.xml
+    content = content.replace(
+      /(setup_version=")([^"]*)/g,
+      `$1${version}`
+    );
+
+  }
+
+  fs.writeFileSync(filePath, content);
+}
+
+// Update each file
+filesToUpdate.forEach(updateVersionInFile);
diff --git a/view/frontend/layout/bobgo_tracking_index.xml b/view/frontend/layout/bobgo_tracking_index.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e36faa5492b864f1f27524486ba0ce148a364b64
--- /dev/null
+++ b/view/frontend/layout/bobgo_tracking_index.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="2columns-left" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
+    <update handle="customer_account"/>
+    <head>
+        <title>
+            Track my order
+        </title>
+    </head>
+    <body>
+        <referenceContainer name="content">
+            <block class="BobGroup\BobGo\Block\TrackingBlock" name="bobgo.tracking.index" template="BobGroup_BobGo::tracking/index.phtml" cacheable="false" />
+        </referenceContainer>
+    </body>
+</page>
diff --git a/view/frontend/layout/customer_account.xml b/view/frontend/layout/customer_account.xml
new file mode 100644
index 0000000000000000000000000000000000000000..701335df1dc4d481523171edc19e24bbac950feb
--- /dev/null
+++ b/view/frontend/layout/customer_account.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
+    <body>
+        <referenceBlock name="customer_account_navigation">
+            <!-- Add conditional menu to the end of the sidebar -->
+            <block class="BobGroup\BobGo\Block\TrackOrderLink" name="customer-account-navigation-tracking">
+                <arguments>
+                    <argument name="path" xsi:type="string">bobgo/tracking/index</argument>
+                    <argument name="label" xsi:type="string">Track my order</argument>
+                </arguments>
+            </block>
+        </referenceBlock>
+    </body>
+</page>
diff --git a/view/frontend/templates/tracking/index.phtml b/view/frontend/templates/tracking/index.phtml
new file mode 100644
index 0000000000000000000000000000000000000000..5895f01a27f33217c05c2519b14a57435511d8bf
--- /dev/null
+++ b/view/frontend/templates/tracking/index.phtml
@@ -0,0 +1,127 @@
+<?php
+$shipmentData = $this->getResponse();
+?>
+
+<style>
+    .track-order-container {
+        max-width: 600px;
+        margin: auto;
+        padding: 20px;
+        border: 1px solid #ddd;
+        background-color: #f9f9f9;
+    }
+
+    .tracking-details h2 {
+        margin-top: 20px;
+    }
+
+    .tracking-details p {
+        margin: 5px 0;
+    }
+
+    footer {
+        margin-top: 20px;
+        font-size: 0.9em;
+        text-align: center;
+    }
+
+    footer img {
+        display: block;
+        margin: 10px auto;
+    }
+</style>
+
+<div class="track-order-container">
+    <?php if (empty($shipmentData)) : ?>
+        <form action="<?php echo $this->getUrl('bobgo/tracking/index'); ?>" method="post" class="track-order-form">
+            <div class="field">
+                <label for="order_reference"><?php echo __('Order Number/Tracking Reference:'); ?></label>
+                <input type="text" id="order_reference" name="order_reference" required>
+            </div>
+            <br>
+            <div class="actions-toolbar">
+                <button type="submit" class="action submit primary"><?php echo __('Track Order'); ?></button>
+            </div>
+        </form>
+    <?php endif; ?>
+
+    <?php if ($shipmentData && is_array($shipmentData)) : ?>
+        <div class="tracking-details">
+            <h2><?php echo __('Shipping Details'); ?></h2>
+
+            <?php if (isset($shipmentData['shipment_tracking_reference'])) : ?>
+                <p><strong><?php echo __('Shipment:'); ?></strong> <?php echo $shipmentData['shipment_tracking_reference']; ?></p>
+            <?php endif; ?>
+
+            <?php if (isset($shipmentData['order_number'])) : ?>
+                <p><strong><?php echo __('Order:'); ?></strong> <?php echo ltrim($shipmentData['order_number'], '0'); ?></p>
+            <?php endif; ?>
+
+            <?php if (isset($shipmentData['courier_name'])) : ?>
+                <p><strong><?php echo __('Courier:'); ?></strong> <?php echo $shipmentData['courier_name']; ?></p>
+            <?php endif; ?>
+
+            <br>
+            <h2><?php echo __('Tracking Details'); ?></h2>
+
+            <?php if (isset($shipmentData['status']) && isset($shipmentData['status_friendly'])) : ?>
+                <?php if ($shipmentData['status'] == 'pending-collection') : ?>
+                    <p><?php echo 'Your shipment will be collected soon. Please check back later for more information.' ?></p>
+                    <p><strong><?php echo __('Current Status:'); ?></strong> <?php echo $shipmentData['status_friendly']; ?></p>
+                <?php elseif (in_array($shipmentData['status'], ['cancelled-by-courier', 'cancelled'])) : ?>
+                    <p><?php echo 'The shipment has been cancelled.'; ?></p>
+                    <p><strong><?php echo __('Current Status:'); ?></strong> <?php echo $shipmentData['status_friendly']; ?></p>
+                <?php else : ?>
+                    <?php if (empty($shipmentData['checkpoints'])) : ?>
+                        <p><?php echo 'Tracking information is not yet available. Please check back later for more information.'; ?></p>
+                    <?php else : ?>
+                        <p><?php echo 'Tracking information is available below:'; ?></p>
+                        <table id="table_checkpoints">
+                            <thead>
+                            <tr>
+                                <th><?php echo __('Date and Time'); ?></th>
+                                <th><?php echo __('Status'); ?></th>
+                                <th><?php echo __('Message'); ?></th>
+                            </tr>
+                            </thead>
+                            <tbody>
+                            <?php foreach ($shipmentData['checkpoints'] as $checkpoint) : ?>
+                                <tr>
+                                    <td>
+                                        <?php
+                                        $timeDate = new DateTime($checkpoint['time']);
+                                        echo $timeDate->format('Y M d, H:i');
+                                        ?>
+                                    </td>
+                                    <td><strong><?php echo $checkpoint['status_friendly']; ?></strong></td>
+                                    <td><?php echo $checkpoint['message']; ?></td>
+                                </tr>
+                            <?php endforeach; ?>
+                            </tbody>
+                        </table>
+                    <?php endif; ?>
+                <?php endif; ?>
+            <?php endif; ?>
+        </div>
+
+    <br>
+        <footer>
+            <p>
+                <?php
+                echo sprintf(
+                    __('For additional information, please contact %s (%s) and quote tracking reference %s.'),
+                    $shipmentData['courier_name'],
+                    $shipmentData['courier_phone'],
+                    $shipmentData['id']
+                );
+                ?>
+            </p>
+            <img id="show_branding" class="image"
+                 src="https://ik.imagekit.io/z1viz85yxs/prod-v3/bobgo/corporate-identity/bobgo_logo_smart_shipping.png?tr=w-400"
+                 alt="Bob Go logo"  style="width: 200px;">
+        </footer>
+    <?php else : ?>
+    <br>
+        <p><?php echo __('No tracking data available.'); ?></p>
+    <?php endif; ?>
+</div>