From the incoming order to the reported shipmentAll articles

From the incoming order to the reported shipment

Partial deliveries are the norm in parts trading. This case shows why decision and shipment are line-based rather than order-based.

Published: 2026-09-12Reading time: 4 mintapinomahub API & workflows
API & processesAPIPricing & valuationLogistics & inventory

An order with three lines arrives. Two parts are on the shelf, the third cannot be found on recount. A system that can only accept or reject the whole order now forces a bad decision: cancel everything or promise something that is not there.

From the incoming order to the reported shipmentInput: an order raised on a channel that has to land in your own system 1. Collect the orders (GET /commerce/v1/orders): Paged with nextCursor; the cursor pagination is stable 2. Read the order (GET /commerce/v1/orders/{salesOrderId}): lines, totals, taxes, fees plus shipTo and billTo reported separately 3. Decide (POST /commerce/v1/orders/{salesOrderId}/decision): Accept or reject per line with a reasonCode instead of silent lapsing 4. Report the shipment (POST /commerce/v1/shipments): carrierCode, trackingReference and shippedAt per shipment, plus the lines with quantities Output: a decision per line and a reported shipment with quantities and trackingReference Partial quantities are the norm, not the exception. A shipment names the shipped lines with quantities and keeps partial delivery traceable.From the incoming order to the reported shipmentInput: an order raised on a channel that has to land in your own system01Collect the ordersGET /commerce/v1/ordersPaged with nextCursor; the cursor pagination is stable02Read the orderGET /commerce/v1/orders/{salesOrderId}lines, totals, taxes, fees plus shipTo and billTo reported separately03DecidePOST /commerce/v1/orders/{salesOrderId}/decisionAccept or reject per line with a reasonCode instead of silent lapsing04Report the shipmentPOST /commerce/v1/shipmentscarrierCode, trackingReference and shippedAt per shipment, plus the lines with quantitiesOutput: a decision per line and a reported shipment with quantities and trackingReferencePartial quantities are the norm, not the exception. A shipment names the shipped lines with quantities and keepspartial delivery traceable.
Four calls from collecting to shipping. Decisions and shipments are per line, not per order.

That is why decision and shipment are line-based in this contract. The partial quantity is not a special case with a workaround but the intended route — and collection uses a cursor pagination the contract describes as stable.

SurfaceRoles
CommerceParts trading, Vehicle trading, Software vendor

What this case requires

  • A stored cursor. With the last nextCursor received you continue the paged fetch; the reconciliation, by contrast, works with its own checkpoints.
  • A mapping of lines to your warehouse. Deciding per line requires knowing per line what is available.
  • Reasons you can stand behind. A rejection carries a reasonCode.
  • A willingness to ship partial quantities. Delivering only in full gives away the two lines that are there.

The sequence

The table names the responsible call per stage and what exists afterwards. The reasoning for why a stage cannot be skipped follows below it.

The call chain of this use case
StageCallWhat exists afterwards
Collect the ordersGET /commerce/v1/ordersPaged with nextCursor; the cursor pagination is stable
Read the orderGET /commerce/v1/orders/{salesOrderId}lines, totals, taxes, fees plus shipTo and billTo reported separately
DecidePOST /commerce/v1/orders/{salesOrderId}/decisionAccept or reject per line with a reasonCode instead of silent lapsing
Report the shipmentPOST /commerce/v1/shipmentscarrierCode, trackingReference and shippedAt per shipment, plus the lines with quantities

Why each stage is needed

  1. Collect the orders. GET /commerce/v1/orders returns pages with a nextCursor. The contract describes this cursor pagination as stable.
  2. Read the order. GET /commerce/v1/orders/{salesOrderId} returns lines, totals, taxes and fees plus shipTo and billTo separately. The separation matters for accounting: a fee is not a discount, and a shipping charge is not an item price.
  3. Decide. POST /commerce/v1/orders/{salesOrderId}/decision takes acceptance or rejection per line with a reasonCode and a quantity. Instead of an order lapsing silently, there is a named decision here; whether it is acknowledged is shown by acknowledgementStatus.
  4. Report the shipment. POST /commerce/v1/shipments takes salesOrderId, the lines with quantities, carrierCode, trackingReference and shippedAt. Line-accurate, because two parts may go out today and one next week without the order losing its state.
Report a partial shipment line by line
curl -X POST \
  -H 'X-Api-Key: <API_KEY>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: sendung-4711-position-1' \
  -d '{"salesOrderId":"<salesOrderId>","lines":[{"lineId":"<lineId>","quantity":1}],"carrierCode":"DHL","trackingReference":"00340434","shippedAt":"2026-09-12T09:30:00Z"}' \
  'https://commerce-preview.invalid/commerce/v1/shipments'

What you end up with

What remains is an order with a decision per line and reported shipments; discrepancies in order and shipment state between channel and your system are established by a reconciliation, which is not yet activated in the contract. Added to that is a customer who receives a partial delivery with tracking instead of a cancellation. The rejected line carries a reason you can read back.

Where to find this in the documentation

The binding field lists, error codes and sample responses live in this surface’s OpenAPI contract at docs.tapinomahub.com (tapinoma-commerce). All use cases arranged by surface and role: overview of the use cases.

Frequently asked

Do I have to store the cursor?

To continue fetching, yes: the stored nextCursor gets you the next page. Discrepancies between source and target are established by the reconciliation through its own checkpoints, not by the order cursor.

Can I reject a single line?

That is precisely why the decision is line-based. It names quantity and reason per line; the contract does not specify what happens to the remaining lines.

Why are fees kept in a field of their own?

Because they are something other than the item price: order and line each carry their own fees field, on the line separate from unitPrice and itemSubtotal. Netting them off means you can no longer trace the individual fee amounts separately later.