Picking ingredients

With ingredient picking on, material leaves stock when it is picked for a manufacturing order (MO), before production. Completions then consume only picked material. The last completion consumes every remaining pick, unless you lower what was used: the difference goes back to stock. This guide continues the e-bike workshop from Manufacturing orders: plan and record: MO 19802886 for 10 City e-bikes.

🚧

Beta. The picking endpoints may change before General Availability.

Before you start

  • Ingredient picking is turned on in the app, under Settings > Manufacturing.
  • We recommend turning on Negative stock prevention under Settings > Preferences, so a pick that would take stock below zero is refused with 422 INVENTORY_SETTINGS_VIOLATED. It checks an item's total stock; for batch- and serial-tracked ingredients also turn on Negative stock prevention (traced stock), otherwise a pick without batches can take a batch below zero.

Pick everything the order needs

The kit for 10 bikes is ready at the workbench. Pick everything the order still needs:

curl -X POST https://api.katanamrp.com/v1/manufacturing_orders/19802886/pick_all \
  -H "Authorization: Bearer $KATANA_API_KEY" -H "Content-Type: application/json" \
  -d '{"picked_date": "2026-10-27T11:47:00.000Z"}'

Each recipe row is picked up to its total_actual_quantity (or plan), less what is already picked. Batches, serial numbers and bins pre-assigned on the recipe rows are taken first; the rest comes from stock following the location's settings. The response lists the picks, one per recipe row:

[
  {
    "id": 2756101,
    "manufacturing_order_id": 19802886,
    "manufacturing_order_recipe_row_id": 113295301,
    "quantity": "10",
    "picked_date": "2026-10-27T11:47:00.000Z",
    "traceability": [
      {"batch_id": 3871201, "serial_number_id": null, "bin_location_id": null, "quantity": "8"},
      {"batch_id": 3871202, "serial_number_id": null, "bin_location_id": null, "quantity": "2"}
    ]
  }
]

pick_all is all or nothing. If stock can't cover everything, nothing is picked, and each short recipe row is listed with its ingredient's variant_id and shortfall:

{
  "error": {
    "statusCode": 422,
    "code": "PICK_ALL_NOT_IN_STOCK",
    "message": "Stock cannot cover everything the order still needs",
    "details": {"rows": [{"manufacturing_order_recipe_row_id": 113295302, "variant_id": 24890117, "shortfall": "4"}]}
  }
}

Pick the rows that are in stock with pick, and the rest when it arrives.

Pick what you actually took

When the floor reports exactly what it took, send it per recipe row with the batches, serial numbers and bins it came from. Leave out traceability for untracked ingredients:

curl -X POST https://api.katanamrp.com/v1/manufacturing_orders/19802886/pick \
  -H "Authorization: Bearer $KATANA_API_KEY" -H "Content-Type: application/json" \
  -d '{
    "rows": [
      {"manufacturing_order_recipe_row_id": 113295301, "quantity": "10",
       "traceability": [{"batch_id": 3871201, "quantity": "8"}, {"batch_id": 3871202, "quantity": "2"}]},
      {"manufacturing_order_recipe_row_id": 113295304, "quantity": "80"}
    ]
  }'

Pick as often as needed; each call adds to what is picked. If you pick more than a row needs, the row's total_actual_quantity is raised to the picked total.

See what is picked

Picks are production ingredients without a production:

curl "https://api.katanamrp.com/v1/manufacturing_order_production_ingredients?manufacturing_order_ids=19802886" \
  -H "Authorization: Bearer $KATANA_API_KEY"

Rows with production_id: null are picked and waiting; rows with a production_id were used by that completion.

Complete in parts from picked material

Completions work as described in Completing manufacturing orders, with one difference: they consume only picked material. Finishing 4 bikes with POST /manufacturing_order_productions and no ingredients takes each row's share for 4 bikes from its picks, capped at what is picked. Sent ingredients can't exceed what is picked and waiting on a row.

Finish the order

Setting the order to DONE consumes the remaining picks. It is refused with INGREDIENTS_NOT_FULLY_PICKED unless every recipe row is picked up to its quantity:

  • Pick the rest with pick_all, then set the order to DONE.
  • Finish with what's picked: set each short row's total_actual_quantity to what is picked, then set the order to DONE. The rest of the plan is dropped.

If the bikes used less than was picked, lower total_actual_quantity before DONE: the 4 bolts not used go back to stock, recorded as a production ingredient with a negative quantity on the completion.

Undo a pick

Undo a pick that was a mistake, such as the wrong batch or 2 motors too many. An undone pick is deleted from the order and from the stock history, and stock from its pick date on is recalculated:

curl -X POST https://api.katanamrp.com/v1/manufacturing_orders/19802886/unpick \
  -H "Authorization: Bearer $KATANA_API_KEY" -H "Content-Type: application/json" \
  -d '{"production_ingredient_ids": [2756102]}'

Each pick goes back whole. If picking had raised the row's total_actual_quantity, it comes back down. Refusals name what to fix:

CodeMeaning
PICK_ALREADY_USEDA completion used the pick (details.production_ingredient_ids). Revert that completion first.
PICK_LINKED_TO_UNITSParts of the pick are linked to output serial numbers (details.picks). Unlink them first.

A pick dated in a closed inventory period can't be undone either; the request is refused with 422.

To undo every pick the order hasn't used, for example when it is postponed, call POST /manufacturing_orders/19802886/unpick_unused. Picks with linked parts and picks in a closed inventory period stay picked.

Undoing is for corrections. To give back material picked for the order but not used, complete the order with the lower quantity instead: that return is recorded as a stock movement.


Did this page help you?