I have created a custom field 'item_serial_number' in shipment item table(sales_shipment_item). db_schema.xml =>

<?xml version="1.0"?>
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
    <table name="sales_shipment_item" resource="sales" engine="innodb" comment="Sales Flat Shipment Item">
        <column xsi:type="text" name="item_serial_number" nullable="true" comment="Item Serial Number"/>

I have also added it in extension_attributes.xml

    <?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Api/etc/extension_attributes.xsd">
   <extension_attributes for="Magento\Sales\Api\Data\ShipmentItemCreationInterface">
       <attribute code="item_serial_number" type="string"/>

I am saving this field while creating shipment from API(rest/V1/order/order_id/ship). API Body =>

  "items": [
      "order_item_id": 236,
      "qty": 1,
      "extension_attributes": {
        "item_serial_number": "sfsdfgdgw33ds"
  "tracks": [
      "track_number": "UB601-21B012064",
      "title": "shyftgo",
      "carrier_code": "shyftgo"

But somehow this extension attribute is not saving in table(sales_shipment_item). No error is showing, shipment is creating successfully.

I am using Magento 2.3.5 -p1.

Please let me know, what should I do? Or any other alternate solution to achieve it.

  • Can you add the custom filed saving (Extention attribute) code in question? Commented Dec 27, 2021 at 6:45
  • @JitendraPatel Do I need to write code for saving field, I haven't added code for saving it? Commented Dec 27, 2021 at 10:04
  • @Prabat Singh pls check this reference link where you find the plugin code in which saving process happening for custom extension attributes. store.magenest.com/blog/create-expose-extension-attributes Commented Dec 27, 2021 at 10:29

1 Answer 1


My first answer was not right, apologies

the idea is to follow your track indeed using an extension attributes so that the request from the API contains the serial number for the shipment item.

Then, to persist this serial item, you need a plugin to run on the model \Magento\Sales\Model\Order\ShipmentDocumentFactory

I use the file di.xml like below:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Sales\Model\Order\ShipmentDocumentFactory">
        <plugin name="os_shiptment_document" type="Mbs\ShipApi\Plugin\ShipmentDocument" />

then, the plugin code is as follows:

     * ShipmentDocument constructor.
     * @param \Magento\Sales\Api\Data\ShipmentItemInterfaceFactory $shipmentItemInterfaceFactory
     * @param \Magento\Sales\Model\Order\Shipment\ItemRepository $shipmentItemRepository
    public function __construct(
        \Magento\Sales\Api\Data\ShipmentItemInterfaceFactory $shipmentItemInterfaceFactory,
        \Magento\Sales\Model\Order\Shipment\ItemRepository $shipmentItemRepository
    ) {
        $this->shipmentItemInterfaceFactory = $shipmentItemInterfaceFactory;
        $this->shipmentItemRepository = $shipmentItemRepository;

    public function afterCreate(
        \Magento\Sales\Model\Order\ShipmentDocumentFactory $subject,
        \Magento\Sales\Api\Data\ShipmentInterface $result,
        OrderInterface $order,
        array $items = [],
        array $tracks = [],
        ShipmentCommentCreationInterface $comment = null,
        $appendComment = false,
        array $packages = [],
        ShipmentCreationArgumentsInterface $arguments = null
    ) {
        if ($items) {
            $shipmentItems = $result->getItems();
            if (is_array($shipmentItems)) {
                foreach ($shipmentItems as $shipmentItem) {
                    $requestItem = $this->getRequestItem($items, $shipmentItem);
                    if ($requestItem) {
                        $shipmentItem->setData('item_serial_number', $requestItem->getExtensionAttributes()->getItemSerialNumber());

        return $result;

     * @param array $items
     * @param $shipmentItem
     * @return mixed
    private function getRequestItem(array $items, $shipmentItem)
        foreach ($items as $item) {
            if ($item->getOrderItemId() == $shipmentItem->getOrderItemId()) {
                return $item;
  • Thanks @Herve Tribouilloy. It works like a charm! Commented Jan 5, 2022 at 13:06

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.