Skip to main content
Solved

Contract REST API: How can we split a kit component allocation across two warehouse locations?

  • August 4, 2026
  • 5 replies
  • 46 views

Jeff96
Captain II
Forum|alt.badge.img+5

We are using Acumatica 2025 R2 and the contract-based REST API.

We created a custom endpoint exposing:

Shipment → ShipmentDetail → Allocations

We need to split one component of a non-stock kit across two warehouse locations while keeping everything on one shipment line.

Example:

  • Shipment line: KIT-001, Shipped Qty. 2
  • COMPONENT-A requirement: 4 units at BIN-A
  • COMPONENT-B requirement: 2 units at BIN-B

Desired result:

  • COMPONENT-A: 2 units at BIN-A and 2 units at BIN-C
  • COMPONENT-B: 2 units at BIN-B, either as one allocation or two allocations of 1 each
  • Kit shipment line remains at Shipped Qty. 2

The equivalent operation works manually on the Shipments screen.

Non-kit control test

Using the custom endpoint, we successfully split a regular stock-item shipment line by:

  1. Reducing the existing allocation quantity.
  2. Inserting a second allocation.
  3. Updating the newly assigned SplitLineNbr to the desired location in a second PUT.

The request uses:

PUT /entity/WMS/24.200.001/Shipment?$expand=ShipmentDetail/Allocations

Therefore, the endpoint can update and insert shipment allocations successfully.

Kit test

For the kit line, we reduced COMPONENT-A from quantity 4 to 2 and inserted another COMPONENT-A allocation for quantity 2 at BIN-C.

During processing, Acumatica correctly created these temporary results:

  • COMPONENT-A: 2 at BIN-A
  • COMPONENT-A: 2 at BIN-C
  • Existing COMPONENT-B allocation reduced from 2 to 1
  • New COMPONENT-B allocation created for quantity 1

However, the automatically generated COMPONENT-B allocation has a blank Location field. The request fails with:

Inserting 'Shipment Line Split' record raised at least one error.

and:

'Location' cannot be empty.

The entire transaction then rolls back.

We cannot update the generated component allocation in a second request because it is never committed. We also cannot address it in the original request because its SplitLineNbr does not exist before the PUT. Including another unkeyed COMPONENT-B row causes Acumatica to treat it as additional kit demand and generate more component allocations.

Questions

  1. Is there a supported contract-based REST API method for completing the automatically generated kit-component allocation before the transaction is committed?
  2. Is there another entity, action, PATCH operation, or endpoint configuration intended for this scenario?
  3. If customization is required, would the recommended solution be a custom action on SOShipmentEntry that performs the split and assigns locations to all generated component splits within the same graph session?

The final allocation structure is valid because the same operation can be completed and confirmed through the Shipments screen. The problem appears to be that the REST import process cannot address the component split created during the current request.

Best answer by dnavasardyan37

Hi ​@Jeff96  your option 3 is the way.

The reason is basically what you already diagnosed. When you touch a kit component allocation, SOShipmentEntry re-explodes the kit and regenerates sibling component splits inside the same graph session. Those new rows only exist in the cache, hey have no SplitLineNbr for the import mapper to bind to, and the mapper only walks the payload you sent. So the regenerated COMPONENT-B row never gets a Location, LocationID is required on SOShipLineSplit, and the whole thing rolls back. There's no PATCH or partial-commit escape hatch that changes that, the contract layer is one save per request.

Your non-kit test working is the tell. No re-explosion means no orphan rows.

So: custom action on SOShipmentEntry, exposed on your endpoint. Something along the lines of taking a payload of component + qty + location tuples, then inside the action:

  • do all your split inserts/updates on Base.Transactions / the splits view
  • after the kit explosion settles, loop the splits cache and fill in LocationID on any split where it came back null (default from the item's warehouse default location, or from whatever you passed in)
  • then Base.Actions.PressSave()

Everything lives in one graph session, so the generated rows are addressable before commit. That's exactly what the Shipments screen is doing when you do it by hand, the UI gets to touch the cache between the explosion and the save, and REST doesn't.

One gotcha: run your location assignment in a loop until no null-location splits remain, not just once. Adjusting one component can trigger another round of explosion depending on the kit setup.

5 replies

jinin
Pro I
Forum|alt.badge.img+12
  • Pro I
  • August 5, 2026

Hi ​@Jeff96,

It appears to be an API limitation.

When the Shipped Qty of a kit line is updated, the system performs the normal auto-allocation process and resolves the inventory locations. However, when a component split is inserted through the API, the kit cascade copies the quantity to the sibling components but does not assign a LocationID. As a result, COMPONENT-B is created with a blank location.

1. No — the generated row's SplitLineNbr is assigned in the same transaction, so your payload can't reference it.
2. Nothing dedicated. Before customizing, try setting a Default Issue From location for COMPONENT-B on IN204500 so the generated split has a fallback.
3. Yes — custom action on SOShipmentEntry, sweep Base.splits and set LocationID on any null-location split before Persist.

Better to raise this with Acumatica support. Since the UI allows this scenario while the API does not provide equivalent functionality, it appears to be a valid API parity gap.


Forum|alt.badge.img+4
  • Jr Varsity II
  • August 5, 2026

Hi ​@Jeff96 ,

The REST API cannot address auto-generated kit-component splits mid-transaction. There's no built-in workaround.

Answers for your questions-

1.No. The contract-based REST API processes the entire entity graph in a single unit of work. There is no hook to intervene between the kit-explosion logic (which creates the blank-location split) and the RowPersisting validation that rejects it. The API has no mechanism to address records that don't yet exist at request time.
2.No built-in option covers this. Specifically:
- PATCH behaves the same as PUT for nested entities — same transaction boundary.
- Actions like ConfirmShipment run after persistence, not during.
- Exposing the component allocations as a separate top-level entity won't help because the kit rebalancing logic fires inside the same SOShipmentEntry graph Persist() call regardless of how you got there.
- The Screen-Based API (SOAP) has the same problem since it also goes through SOShipmentEntry.
3. Yes. A custom action on SOShipmentEntry (or a dedicated custom graph/long-running process) is the correct Solution: Create a custom action on SOShipmentEntry that:
1. Modifies the component splits
2. Catches/fixes any auto-generated splits (blank LocationID) via RowInserting<SOShipLineSplit> event or by iterating the cache before Save.Press()
3. Persists everything in one graph session
Expose the action on your custom endpoint and call it via POST. This mirrors what the UI does across multiple round-trips, but in a single server-side operation.

Hope above helps!!


Forum|alt.badge.img+3
  • Captain II
  • August 5, 2026

From your testing, it does not appear that the issue is with your endpoint configuration. The successful non-kit scenario demonstrates that nested allocation updates are functioning correctly.

Instead, the limitation seems specific to graph-generated kit component splits, whose keys are not available until after the import engine has already processed the payload. As a result, required fields on those generated records cannot be supplied through the same REST request.

If anyone has successfully implemented this using only the standard contract-based REST API (without graph customization), I'd be interested to know the approach, as I haven't encountered a supported pattern that allows the REST importer to populate automatically generated kit component allocations before validation occurs.


dnavasardyan37
Jr Varsity I
Forum|alt.badge.img+4
  • Jr Varsity I
  • Answer
  • August 5, 2026

Hi ​@Jeff96  your option 3 is the way.

The reason is basically what you already diagnosed. When you touch a kit component allocation, SOShipmentEntry re-explodes the kit and regenerates sibling component splits inside the same graph session. Those new rows only exist in the cache, hey have no SplitLineNbr for the import mapper to bind to, and the mapper only walks the payload you sent. So the regenerated COMPONENT-B row never gets a Location, LocationID is required on SOShipLineSplit, and the whole thing rolls back. There's no PATCH or partial-commit escape hatch that changes that, the contract layer is one save per request.

Your non-kit test working is the tell. No re-explosion means no orphan rows.

So: custom action on SOShipmentEntry, exposed on your endpoint. Something along the lines of taking a payload of component + qty + location tuples, then inside the action:

  • do all your split inserts/updates on Base.Transactions / the splits view
  • after the kit explosion settles, loop the splits cache and fill in LocationID on any split where it came back null (default from the item's warehouse default location, or from whatever you passed in)
  • then Base.Actions.PressSave()

Everything lives in one graph session, so the generated rows are addressable before commit. That's exactly what the Shipments screen is doing when you do it by hand, the UI gets to touch the cache between the explosion and the save, and REST doesn't.

One gotcha: run your location assignment in a loop until no null-location splits remain, not just once. Adjusting one component can trigger another round of explosion depending on the kit setup.


Jeff96
Captain II
Forum|alt.badge.img+5
  • Author
  • Captain II
  • August 10, 2026

Thank you everyone. I got this solved through the customization.