Skip to main content

Confirm or cancel a fulfilment

Only for warehouses that validate the shippings

The two mutations on this page apply only to projects where the external warehouse must validate each shipping before OMS ships it: the warehouse reports what was actually packed, and OMS books the carrier on that basis. This is a per-project choice, configured by Calicantus during onboarding.

note

The ids, SKUs, serial and batch numbers in these examples are placeholders — replace them with your own.

When the warehouse validates the shippings, OMS does not book the carrier as soon as the order is confirmed: the shipping waits, with fulfillmentStatus: pending and bookingStatus: pending (see Order and shipping statuses), for the warehouse to declare how the goods were packed. The warehouse closes this step with one of two mutations:

Each shipping accepts one declaration, with no follow-up calls: "partial" refers to the goods packed compared to the ones ordered, not to a confirmation in several steps. A shipping that is not waiting for the warehouse (booking already started, fulfilment not tracked, already declared) rejects both mutations with a BAD_REQUEST error.

Confirm the fulfilment

Use shippingFulfillmentConfirm to declare the parcels prepared and, when the shipping is not packed in full, the quantities packed per line. The mutation accepts a list of ShippingFulfillmentConfirmParcelInput and, optionally, a list of ShippingFulfillmentConfirmLineInput objects — their references list all the available fields. It returns the FulfillmentPacking created.

shippingId is the id of an entry of Order.shippings, and the shippingLineId values of lines are the id of that shipping's itemLines, the item lines the warehouse handles. Read them with the order query:

Request
query shippingLinesToDeclare {
  order(id: "9347") {
    id
    shippings {
      id
      itemLines {
        id
        quantity
        orderLine {
          sku
        }
      }
    }
  }
}
Response
{
  "data": {
    "order": {
      "id": "9347",
      "shippings": [
        {
          "id": "9722",
          "itemLines": [
            {
              "id": "26153",
              "quantity": 2,
              "orderLine": {
                "sku": "SKU-1"
              }
            },
            {
              "id": "26154",
              "quantity": 1,
              "orderLine": {
                "sku": "SKU-2"
              }
            }
          ]
        }
      ]
    }
  },
  "extensions": {
    "queryComplexity": 9,
    "bucketBalance": 9991,
    "bucketRestoreRate": 100
  }
}

Field notes:

  • parcels describes the parcels handed to the carrier: kind, dimensions in centimeters and net weight in grams, as for ShippingParcel. At least one parcel is required and every value must be positive. They replace the parcels the shipping had.
  • lines is optional: omit it to fulfil the whole shipping. When present, list the item lines you packed with the quantity packed, which cannot exceed the line quantity: a line not listed has nothing packed (listing it with quantity: 0 is equivalent), and the rest of a line's quantity stays unfulfilled.
  • The same shippingLineId can appear more than once to declare different serialNumber or batchNumber values; a line with a serialNumber covers one unit. A batchNumber unknown to OMS is created. userName is the operator who prepared the line, informational only.
  • If no item is packed at all, use the cancel mutation instead: a confirmation with every quantity at 0 is rejected.

After the confirmation the shipping's fulfillmentStatus is completed when every item was packed, partial otherwise; fulfilledQuantity and unfulfilledQuantity are set on each shipping line, and the booking proceeds with the parcels declared: bookingStatus moves from pending to ready, then confirmed when the shipping label (waybill) is generated.

Fulfil the whole shipping

Without lines, every item line is fulfilled in full.

Response
{
  "data": {
    "shippingFulfillmentConfirm": {
      "id": "12",
      "createdAt": "2026-09-03T12:53:22.814Z",
      "shipping": {
        "id": "9724",
        "number": "1",
        "fulfillmentStatus": "completed",
        "bookingStatus": "pending",
        "parcels": [
          {
            "id": "150",
            "kind": "box",
            "weight": 2500.0,
            "length": 40.0,
            "width": 30.0,
            "height": 20.0,
            "tailLiftRequired": false
          }
        ]
      },
      "lines": [
        {
          "id": "37",
          "quantity": 2,
          "serialNumber": null,
          "userName": null,
          "batch": null,
          "shippingLine": {
            "id": "26157",
            "quantity": 2,
            "fulfilledQuantity": 2,
            "unfulfilledQuantity": 0,
            "orderLine": {
              "sku": "SKU-1"
            }
          }
        },
        {
          "id": "38",
          "quantity": 1,
          "serialNumber": null,
          "userName": null,
          "batch": null,
          "shippingLine": {
            "id": "26158",
            "quantity": 1,
            "fulfilledQuantity": 1,
            "unfulfilledQuantity": 0,
            "orderLine": {
              "sku": "SKU-2"
            }
          }
        }
      ]
    }
  },
  "extensions": {
    "queryComplexity": 31,
    "bucketBalance": 9934,
    "bucketRestoreRate": 100
  }
}

The bookingStatus in the response is still pending: the booking is picked up right after the confirmation, read the shipping again to follow it.

Fulfil part of the shipping

With lines, declare the quantity packed for each item line: here one of the two units of the first line is packed, the second line is packed in full. The unit not declared is not shipped with this shipping and cannot be declared in a second call.

Request
mutation shippingFulfillmentConfirm {
  shippingFulfillmentConfirm(
    shippingId: "9725"
    parcels: [{ kind: box, weight: 2500, length: 40, width: 30, height: 20 }]
    lines: [
      { shippingLineId: "26159", quantity: 1 }
      { shippingLineId: "26160", quantity: 1 }
    ]
  ) {
    id
    shipping {
      id
      fulfillmentStatus
    }
    lines {
      id
      quantity
      shippingLine {
        id
        quantity
        fulfilledQuantity
        unfulfilledQuantity
      }
    }
  }
}
Response
{
  "data": {
    "shippingFulfillmentConfirm": {
      "id": "13",
      "shipping": {
        "id": "9725",
        "fulfillmentStatus": "partial"
      },
      "lines": [
        {
          "id": "39",
          "quantity": 1,
          "shippingLine": {
            "id": "26159",
            "quantity": 2,
            "fulfilledQuantity": 1,
            "unfulfilledQuantity": 1
          }
        },
        {
          "id": "40",
          "quantity": 1,
          "shippingLine": {
            "id": "26160",
            "quantity": 1,
            "fulfilledQuantity": 1,
            "unfulfilledQuantity": 0
          }
        }
      ]
    }
  },
  "extensions": {
    "queryComplexity": 31,
    "bucketBalance": 9903,
    "bucketRestoreRate": 100
  }
}

Track serial and batch numbers

When you track them, split a shipping line into one entry per serial number or batch: here the first line (2 ordered) is packed for one serialized unit, the second line is packed in full from a stock batch.

Request
mutation shippingFulfillmentConfirm {
  shippingFulfillmentConfirm(
    shippingId: "9726"
    parcels: [
      { kind: box, weight: 2500, length: 40, width: 30, height: 20 }
      { kind: box, weight: 1200, length: 30, width: 20, height: 15 }
    ]
    lines: [
      {
        shippingLineId: "26161"
        quantity: 1
        serialNumber: "SN-0001"
        batchNumber: "LOT-2026-09"
        userName: "Mario Rossi"
      }
      {
        shippingLineId: "26162"
        quantity: 1
        batchNumber: "LOT-2026-09"
        userName: "Mario Rossi"
      }
    ]
  ) {
    id
    shipping {
      id
      fulfillmentStatus
    }
    lines {
      id
      quantity
      serialNumber
      userName
      batch {
        id
        number
      }
      shippingLine {
        id
        fulfilledQuantity
        unfulfilledQuantity
      }
    }
  }
}
Response
{
  "data": {
    "shippingFulfillmentConfirm": {
      "id": "14",
      "shipping": {
        "id": "9726",
        "fulfillmentStatus": "partial"
      },
      "lines": [
        {
          "id": "41",
          "quantity": 1,
          "serialNumber": "SN-0001",
          "userName": "Mario Rossi",
          "batch": {
            "id": "44075",
            "number": "LOT-2026-09"
          },
          "shippingLine": {
            "id": "26161",
            "fulfilledQuantity": 1,
            "unfulfilledQuantity": 1
          }
        },
        {
          "id": "42",
          "quantity": 1,
          "serialNumber": null,
          "userName": "Mario Rossi",
          "batch": {
            "id": "44075",
            "number": "LOT-2026-09"
          },
          "shippingLine": {
            "id": "26162",
            "fulfilledQuantity": 1,
            "unfulfilledQuantity": 0
          }
        }
      ]
    }
  },
  "extensions": {
    "queryComplexity": 31,
    "bucketBalance": 9872,
    "bucketRestoreRate": 100
  }
}

Cancel the fulfilment

Use shippingFulfillmentCancel when no item of the shipping is packed: it takes the shippingId only (the id of the shipping in Order.shippings) and returns the updated Shipping.

After the cancellation the shipping has fulfillmentStatus: cancelled, no parcels and no fulfillmentPacking, and accepts no further declaration.

Response
{
  "data": {
    "shippingFulfillmentCancel": {
      "id": "9720",
      "number": "1",
      "fulfillmentStatus": "cancelled",
      "bookingStatus": "pending",
      "status": null,
      "parcels": [],
      "lines": [
        {
          "id": "26149",
          "quantity": 2,
          "fulfilledQuantity": 0,
          "unfulfilledQuantity": 0
        },
        {
          "id": "26150",
          "quantity": 1,
          "fulfilledQuantity": 0,
          "unfulfilledQuantity": 0
        }
      ],
      "fulfillmentPacking": null
    }
  },
  "extensions": {
    "queryComplexity": 15,
    "bucketBalance": 9938,
    "bucketRestoreRate": 100
  }
}

Relevant permissions

The operations in this page require the following permissions on the API credentials — they are configured for you by Calicantus.

  • shipping:mutation:shipping_fulfillment_confirm
  • shipping:mutation:shipping_fulfillment_cancel
  • order:query:order
  • order:read
  • shipping:read
  • order_line:read