Fulfilling a Sales Order


LOCATE’s default fulfillment process for a sales order consists of four steps: pick, pack, ship, and pickup.

  • In the picking step, inventory for your order is committed from its storage location to a single moving location.
  • In the packing step, picked parts get placed into cartons.
  • In the shipping step, cartons can be palletized.
  • In the pickup step, completed cartons are picked up by the carriers.

LOCATE has a few different levels of automation for fulfilling an issued order. Orders can either be fully autoworked, partially autoworked, or processed step by step. In the following section we will first explain how to manually work an order, step by step, to better understand each part of the process. However, feel free to jump ahead to the Autowork section for a more automated look at order fulfillment.

We can always reference work done to a sales order by embedding fulfillment modules onto our salesorder request. This allows us to easily examine the state of an order, and perform necessary actions on it.

GET /salesorder/[salesorder_id]?embed=picks,packs,ships,pickups

Our first three steps: pick, pack, and ship are most commonly driven by calls to {module}linebyorder with the salesorder ID in the body. For example, to create a pick from an issued salesorder:

POST /picklinebyorder

Body: {“order_id”: [[insert salesorder_id]]}

Note: Order ID’s are sent as an array, allowing operations to be created with multiple orders.


LOCATE has several methods of creating picks (by customer, destination, part, and order). The most common being By Order. We can create a pick for an order with the following call:

POST /picklinebyorder

Body: {“order_id”: [[insert salesorder_id]]}

The double square brackets is to show that the parameter is an array and you will put an integer value in the array.

Once we have our pick ID, we can grab our related picklines by embedding lines on our pick call. In addition to the pickline_id, we will also need to know the location_id of the parts we are committing from. We can do that by embedding “qty_available_for_pick” on each of our parts:

GET /pick/{pick_id}?embed=lines,lines.part.qty_available_for_pick.location

This will return data about each pickline, and we can use the pickline ID to commit each line.

Note: When committing tracked inventory, LOCATE requires that tracking metadata be supplied when committing. See the API Reference for more details on the structure of this data.


After completing our pick, we can perform a similar process to pack our order.

POST /packlinebyorder

Body: {“order_id”: [[insert salesorder_id]]}

The double square brackets is to show that the parameter is an array and you will put an integer value in the array.

Next we will create a carton for our packlines. You can reference the /cartontype endpoint for a comprehensive list of carton types.

POST /pack/{pack_id}/carton

Body: {“cartontype_id”: [carton type ID]}

Next we use the newly created carton_id to move our packlines to our carton. In this example, add_carton_id is our newly created carton’s id, and subtract_location_id is the location the items were picked to in the previous step.

POST /pack/{pack_id}/moveitem

Body: {“add_carton_id”: [carton ID], “order_id”: [sales order ID], “move_all”: 1, “part_id”: [part_id], “qty”: 1, “subtract_location_id”: [current location ID]}

Finally, we finish the packing step.

POST /pack/{pack_id}/finish

Note: The LOCATE setting “start_in_carton” determines where your packing process starts. Typically, “start_in_carton” is disabled, and cartons need to be created for items to be moved into. When enabled all of your items are packed into a single carton upon pack creation. Items can then be moved to new cartons (if necessary) or the pack can be directly finished.

When the “start_in_carton” setting is disabled LOCATE provides the option of autopacking your order. Autopacking will use your item dimensions to pack your order into the most efficient carton size(s). To autopack, simply call:

POST /pack/{pack_id}/autopack


After completing our pack, we can perform a similar process to ship our order.

POST /shiplinebyorder

Body: {“order_id”: [[insert salesorder_id]]}

The double square brackets is to show that the parameter is an array and you will put an integer value in the array.

Simply POST to your shipment with finish to complete the shipping step.

POST /ship/{ship_id}/finish


Once an order is packed into cartons and finishes the ship step, we can no longer run our workflow with just the order id. A carton can contain items from several salesorders, so instead, we allow pickup by carton or carrier, individually or in batches.

To find the pickuplines necessary to create a pickup, we can simply embed them on our salesorder.

GET /salesorder/[salesorder_id]?embed=pickuplines

Once we have our pickupline_ids, marking lines as being picked up is simple.

POST /pickup

Body: {“pickupline_ids”: [[insert pickupline_id]], “site_id”: [insert site_id]}

The double square brackets is to show that the parameter is an array and you will put an integer value in the array.


Autoworking allows you to fulfill a set of tasks for all items on an order at a given site. LOCATE’s autoworking process is non-blocking, autoworked orders are handled in a queue.

To autowork an order in full add autowork to your order call with the parameter full_auto=1. LOCATE will attempt to complete all possible work for an order based on the API callers current site without requiring you to provide specific tasks or steps.

POST /salesorder/[salesorder_id]/autowork

Body: {“full_auto”: 1}

Alternatively you can have LOCATE autoworker only certain tasks to be performed on an order. To get a list of tasks and their associated IDs you can use the following call:

GET /task

When a user autoworks an issued order in the LOCATE UI, the following call is made:

POST /salesorder/[salesorder_id]/autowork

Body: {“task_ids”: [2,3,4]}

This takes our order through pick, pack, and ship, leaving it ready for pickup. LOCATE’s user run autowork stops short of the pickup step, since at that point work becomes difficult to reverse, and we let the user finish the pickup step.

To autowork with pickup simply include pickup in the list of “task_ids” (e.g. [2,3,4,6]).

Alternatively, You can Autowork single tasks, or different combinations of tasks if you want to do any fulfillment steps manually.

Tracking and Carton Details

At the start of packing, cartons are in an open status. Once packing finishes, cartons enter a closed status. Cartons stay in a closed status throughout the ship step. Finally, once pickup finishes, the cartons become locked.

Tracking and carton details can be posted back to the cartons anytime, up until the cartons become locked by pickup. Even if a pack has already been completed, carton, carrier and tracking information can still be posted back to it:

PUT /pack/[pack_id]/carton/[carton_id]

Body: {“tracking_number”: [insert tracking number], “carrier_id”: [insert carrier_id]}

Tracking details can also be sent to the autowork endpoint to have them assigned during the autowork process.

Edge Cases

Not all companies have a workflow that involves Pick, Pack, Ship, and Pickup. Pack or Ship steps can be skipped depending on your workflow, or carrier.

As an example of this, consider Will Call orders. Orders with a carrier of Will Call don’t have a pack or ship step, and move directly to pickup after picking. Optionally, in the carrier settings module, Will Call can be set to include a pack step.

Consider also that several LOCATE settings can change parts of this workflow. For example the setting: “Auto-Create Pick By Order”, automatically creates a pick whenever a salesoder is issued. Processing orders with “Auto-Create Pick By Order” enabled, allows you to start your process with a created pick.