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.
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.
| Surface | Roles |
|---|---|
| Commerce | Parts trading, Vehicle trading, Software vendor |
What this case requires
- A stored cursor. With the last
nextCursorreceived 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.
| Stage | Call | What exists afterwards |
|---|---|---|
| Collect the orders | GET /commerce/v1/orders | Paged with nextCursor; the cursor pagination is stable |
| Read the order | GET /commerce/v1/orders/{salesOrderId} | lines, totals, taxes, fees plus shipTo and billTo reported separately |
| Decide | POST /commerce/v1/orders/{salesOrderId}/decision | Accept or reject per line with a reasonCode instead of silent lapsing |
| Report the shipment | POST /commerce/v1/shipments | carrierCode, trackingReference and shippedAt per shipment, plus the lines with quantities |
Why each stage is needed
- Collect the orders.
GET /commerce/v1/ordersreturns pages with anextCursor. The contract describes this cursor pagination as stable. - Read the order.
GET /commerce/v1/orders/{salesOrderId}returnslines,totals,taxesandfeesplusshipToandbillToseparately. The separation matters for accounting: a fee is not a discount, and a shipping charge is not an item price. - Decide.
POST /commerce/v1/orders/{salesOrderId}/decisiontakes acceptance or rejection per line with areasonCodeand a quantity. Instead of an order lapsing silently, there is a named decision here; whether it is acknowledged is shown byacknowledgementStatus. - Report the shipment.
POST /commerce/v1/shipmentstakessalesOrderId, the lines with quantities,carrierCode,trackingReferenceandshippedAt. Line-accurate, because two parts may go out today and one next week without the order losing its state.
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.
Sources and legal references
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.
