I'm trying to add tracking to orders via the SOAP (V1) interface using the sales_order_shipment.addTrack method - but as the title suggests I'm getting the following error: Invalid carrier specified

The first thing I tried was to use the custom carrier code as such:

'shipmentIncrementId' => $shipmentIncrementId,
'carrier' => 'custom',
'title' => 'My courier',
'trackNumber' => $tracking

(Note that both $shipmentIncrementId and $tracking are correct.)

This produced the aforementioned error.

So I decided to make my own module adding a custom carrier, I followed this tutorial. Most importantly, I've implemented isTrackingAvailable() and made it return true.

Now, interestingly, if I make the call to sales_order_shipment.getCarriers my custom carrier is there, so it should be available! However, when I again make the sales_order_shipment.addTrack call with the following details:

'shipmentIncrementId' => $shipmentIncrementId,
'carrier' => 'name_of_module',
'title' => 'Custom Carrier',
'trackNumber' => $tracking

Where name_of_module is obviously the correct name of the module, returned by getCarriers and this time I've matched the title to the one defined in the module (Custom Carrier).

With this, I still get the same error of Invalid carrier specified! Surely if getCarriers returns this carrier for an order it shouldn't be invalid?

The only place on the web that attempts to document this error is here, as described above I have followed the suggested steps according to that link.

Could anyone point me to where I'm going wrong? Thanks in advance for your help.

P.S. If it makes any difference, I'm trying to avoid adding a new module for every single carrier we use, I'd like to be able to pass through the correct title of the carrier through SOAP and add any tracking number (we don't use any of the predefined carriers in Magento).


The following is the code that calls the API:

            'shipmentIncrementId' => $shipmentIncrementId,
            'carrier' => 'fesp_fixstupidcarriers',
            'title' => 'Custom Carrier',
            'trackNumber' => $tracking,

This uses my custom function, which in turn runs call_user_func_array([$client, 'call'], $arguments);

$arguments comes out as the following array:

    'Custom Carrier',

I'm showing actual data this time, that's a real shipmentIncrementId, the actual carrier code, and the real tracking number.

This function works for all other calls of the API I've tried (about a dozen).

  • What happens if you call the API without the array keys ? Just by giving an array of values in the right order ? Sep 27, 2016 at 10:28
  • The same, only shipmentIncrementId posted. I also tried mocking out my function and doing it directly with and without keys, no change in results either way. Sep 27, 2016 at 10:35
  • 1
    Well i'm out of ideas here. Pretty sure you'll have to go in hardcode debugging mode. Try to check that good article: alanstorm.com/debugging_magento_api_method_calls Sep 27, 2016 at 10:39
  • Thanks, I'll have a look. I'll give you the bounty seeing how helpful you were :) Sep 27, 2016 at 10:50

2 Answers 2


I'm not sure what can cause this but I'm going to give you the steps to debug the problem.

The error

The error you're getting:

Invalid carrier specified.

Comes from the following file: app/code/core/Mage/Sales/Model/Order/Shipment/Api.php in the addTrack() method:

public function addTrack($shipmentIncrementId, $carrier, $title, $trackNumber)
    $shipment = Mage::getModel('sales/order_shipment')->loadByIncrementId($shipmentIncrementId);

    /* @var $shipment Mage_Sales_Model_Order_Shipment */

    if (!$shipment->getId()) {

    $carriers = $this->_getCarriers($shipment);

    if (!isset($carriers[$carrier])) {
        $this->_fault('data_invalid', Mage::helper('sales')->__('Invalid carrier specified.'));

    $track = Mage::getModel('sales/order_shipment_track')


    try {
    } catch (Mage_Core_Exception $e) {
        $this->_fault('data_invalid', $e->getMessage());

    return $track->getId();

As you can see this method does the following:

  • load the shipment
  • get the carriers for the shipment
  • check if the carrier provided is allowed
  • create the tracking
  • add the tracking to the shipment
  • save both tracking and shipment


As you can see, the list of allowed carriers is retrieved via a protected method in that same class _getCarriers :

protected function _getCarriers($object)
    $carriers = array();
    $carrierInstances = Mage::getSingleton('shipping/config')->getAllCarriers(

    $carriers['custom'] = Mage::helper('sales')->__('Custom Value');
    foreach ($carrierInstances as $code => $carrier) {
        if ($carrier->isTrackingAvailable()) {
            $carriers[$code] = $carrier->getConfigData('title');

    return $carriers;

Here how I would start the debugging process.

  1. Add the following line at the beggining of the addTrack() method:

  2. Then add the following line before return $carriers; in the _getCarriers() method:

  3. Call your sales_order_shipment.addTrack and check your var/log/system.log for the result

Case 1: your carrier code is not a key of the carriers array

Two possibilities here:

  • Your carrier is not enabled / allowed for the specified store. Indeed the following code retrieves the list of all carriers but it filters them by store id. Double check the carrier configuration using the scope dropdown:

    $carrierInstances = Mage::getSingleton('shipping/config')->getAllCarriers(
  • Your carrier does not have tracking available. I guess you already did check that but open the model that corresponds to the carrier and check what the isTrackingAvailable() method returns. If such method is not declared in the carrier model, that means it returns false and thus tracking is not available for this carrier.

Case 2: your carrier code is a key of the carrier array

First, ensure that there's no whitespaces around your carrier code. That's the reason why I added the --- before and after the carrier code in the debugging code.

You can further investigate the differences by replacing:

    if (!isset($carriers[$carrier])) {
        $this->_fault('data_invalid', Mage::helper('sales')->__('Invalid carrier specified.'));


foreach ($carriers as $key => $value) {
    Mage::log("checking key: ".$key."---");
    Mage::log("provided key: ".$carrier."---");
if (!isset($carriers[$carrier])) {
    $this->_fault('data_invalid', Mage::helper('sales')->__('Invalid carrier specified.'));

If you're in this case, it's pretty much a typo IMO.

  • Thank you for this, very useful information. I'll investigate and get back to you Sep 22, 2016 at 10:16
  • I'm finally able to come back to this issue, I've added the Mage::log() lines in the relevant places, and this is what I get: Missing argument 2 for Mage_Sales_Model_Order_Shipment_Api::addTrack(), called in /home/account/public_html/app/code/core/Mage/Api/Model/Server/Handler/Abstract.php on line 294 and defined/home/account/public_html/app/code/core/Mage/Sales/Model/Order/Shipment/Api.php (Same for argument 3 and 4) Sep 27, 2016 at 9:33
  • I posted that prematurely, that error is followed by these: Undefined variable: carrier/home/account/public_html/app/code/core/Mage/Sales/Model/Order/Shipment/Api.php Which I guess is caused by the above error, i.e. not getting the arguments. Then we get to the Mage::log() entries, in addTrack() it just returns ------ obviously because $carrier is undefined, then it correctly prints out the array of carriers for the _getCarriers() function. Sep 27, 2016 at 9:35
  • 1
    Considering the above, I have just added Mage::log(func_get_args()); to the top of addTrack() to see what it's actually getting, and as the errors suggest it's only getting the shipmentIncrementId, any ideas why this would be? Sep 27, 2016 at 9:41
  • @SworrubWehttam very interesting. Could you post the exact code that calls the addTrack API in your question please ? Sep 27, 2016 at 9:44

This is pretty much a bad hack job, but for me the API returned the same array of available carriers as the dropdown menu in admin does.


This returned: array(6) { [0]=> object(stdClass)#10 (2) { ["key"]=> string(6) /"custom" ["value"]=> string(13) "Mukailtu arvo" } [1]=> object(stdClass)#16 (2) { ["key"]=> string(3) "dhl" ["value"]=> string(3) "DHL" } [2]=> object(stdClass)#45 (2) { ["key"]=> string(5) "fedex" ["value"]=> string(15) "Federal Express" } [3]=> object(stdClass)#32 (2) { ["key"]=> string(3) "ups" ["value"]=> string(21) "United Parcel Service" } [4]=> object(stdClass)#15 (2) { ["key"]=> string(4) "usps" ["value"]=> string(28) "United States Postal Service" } [5]=> object(stdClass)#36 (2) { ["key"]=> string(6) "dhlint" ["value"]=> string(3) "DHL" } } int(5)

I looked at the code that my carrier is using to save it's tracking code with it's own carrier code (that's not working via API) and it was using this code in Abstract.php


I commented out the check for checking invalid carrier (hack job...) and changed the way carrier & title are decided to match our carrier:

   // if (!isset($carriers[$carrier])) {
    //    $this->_fault('data_invalid', Mage::helper('sales')->__('Invalid carrier specified.'));

    $carrier = $shipment->getShippinglabelsType();
    $title = $shipment->getShippinglabelsTypeName();

    $track = Mage::getModel('sales/order_shipment_track')

Now I can just send an tracking number via API without invalid carrier errors. It would be worth the extra effort to restore the invalid carrier method check and just integrate the shippinglabel code within the error check, but this is a quick way to get things working.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.