Commercial Order data model

What this covers

The conceptual (header-level) structure of a Commercial Order in Order-based Checkout: field groups and how amounts are derived.

Context

  • The Commercial Order is order-first (no technical cart).
  • Beyond DRAFT (editable) vs placed (immutable), it has no intrinsic statuses; overall progression is driven by child Logistic Orders (see OMS lifecycle).

Compatibility note

  • The processing attribute is a legacy field inherited from cart-centric flows (Cart v2).
  • It is not used in Order-based Checkout. If it appears in some responses for backward compatibility, ignore it in new integrations.

🧩 Field groups

Identifiers & scope

  • Order identifier (alphanumeric), Account, Store / Store-view, Currency (ISO 4217), created/updated timestamps.
  • Optional external references (e.g., ERP reference).

Custom fields at creation

  • The create endpoint supports order-level custom fields (customFields[] with customFieldId/customFieldValue and customFieldIdType, defaulting to EXTERNAL_ID). See ORDER-108.

Buyer references & notes

  • Purchase reference (e.g., PO or requisition), buyer notes, additional free-form references through custom fields.

Parties & addresses

  • Shipping address, Billing address, contact person/email/phone.

    Updates while DRAFT use ORDER-215 (shipping) and ORDER-213 (billing).

Aggregated prices over child Logistic Orders

  • orderLogisticPrices (currency, totalPriceWithTax, totalPriceWithoutTax, totalProductTaxAmount, totalProductWithTax, totalProductWithoutTax, totalShippingFeesWithTax, totalShippingFeesWithoutTax, totalShippingTaxAmount, totalTaxAmount).
  • Currency is the one used by underlying Logistic Orders (single currency).

Counts

  • productCount - sum of quantities across all lines of all child Logistic Orders.
  • lineCount - total number of lines across all child Logistic Orders (≠ products; a product can have multiple price lines).

Snapshots

  • customerAccountSnapshot - { externalId, id, name, vatNumber }
  • customerUserSnapshot - { civility, email, externalId, firstName, id, lastName, phone }

Lifecycle timestamps (Commercial Order)

  • createdAt - creation time of the Commercial Order
  • updatedAt - last update time of the Commercial Order
  • validatedAt - time when all child Logistic Orders moved to CREATED (validation moment)
  • lastSyncAt - time of the last successful synchronization via ORDER-223. Updated each time sync completes without blocking warnings. Can be used to decide whether a re-sync is needed (e.g. skip if lastSyncAt is recent).

Legacy attribute (do not use)

  • processing - legacy from Cart v2, not used in Order-based Checkout. May appear in some payloads; ignore.

Source metadata (optional)

  • When initialized from a Quote or from an Operation, a reference to that source is stored so you can trace provenance.

    For Operations, the tenant flag OPERATIONS must be enabled.

Note

This page documents the Commercial Order header-level model (aggregates, counts, snapshots, timestamps).

Lines are not included in ORDER-560 (list) and ORDER-500 (header by id). Use ORDER-561 to read lines. See “Working with Draft Orders ▸ Add lines / Read lines” for line payloads and validations.


🗺️ Object overview

flowchart LR
  O[Commercial Order<br>Identifiers & scope<br>Account • Store/View • Currency]:::root --> H[Header & references<br>PO/Requisition • Notes]:::node
  O --> A[Parties & addresses<br>Shipping • Billing • Contact]:::node
  O --> T[Aggregated prices<br>orderLogisticPrices]:::money
  O --> CNT[Counts<br>productCount • lineCount]:::metric
  O --> SNA[Account snapshot]:::snap
  O --> SNU[User snapshot]:::snap
  O --> LOS[Child Logistic Orders ...]:::lo
  O --> SRC[Source metadata - optional<br>Quote or Operation reference]:::opt

  %% ---------- Styles ----------
  classDef root fill:#e8f1ff,stroke:#2f6feb,stroke-width:2px,color:#0b3d91;
  classDef node fill:#f2f4f7,stroke:#475569,stroke-width:2px,color:#111827;
  classDef money fill:#ecfdf5,stroke:#10b981,stroke-width:2px,color:#064e3b;
  classDef metric fill:#e0f2fe,stroke:#0284c7,stroke-width:2px,color:#0c4a6e;
  classDef snap fill:#f5e9ff,stroke:#8a2be2,stroke-width:2px,color:#3b0764;
  classDef lo fill:#fef9c3,stroke:#eab308,stroke-width:2px,color:#713f12;
  classDef opt fill:#fff4e5,stroke:#f59e0b,stroke-width:2px,color:#7a3e00;

  style O rx:8,ry:8
  style H rx:8,ry:8
  style A rx:8,ry:8
  style T rx:8,ry:8
  style CNT rx:8,ry:8
  style SNA rx:8,ry:8
  style SNU rx:8,ry:8
  style LOS rx:8,ry:8
  style SRC rx:8,ry:8

🧮 Amount math (conceptual, provider-neutral)

Within each Logistic Order

Apply the per-line and header math as usual (unitPrice × qty, discounts, taxes, shipping/duty).

Where shipping fees live

When the Shipping module is active, shipping fees are resolved per Logistic Order (from the shipping price matrix), not line by line. The per-line shipping fields are therefore not populated for orders coming from direct checkout — read the shipping amount on the Logistic Order instead (totalShippingFeesWithTax, totalShippingFeesWithoutTax, totalShippingTaxAmount).

Orders created from a Quote keep exposing shipping per line, because on quote workflows the amount is negotiated line by line. Tenants without the Shipping module keep the existing behaviour.

See Where shipping fees are exposed and Start from a source Operation or Quote.


Commercial Order aggregation

orderLogisticPrices returns the sum of these amounts across all child Logistic Orders:

  • currency, totalPriceWithoutTax / totalPriceWithTax
  • totalProductWithoutTax / totalProductWithTax / totalProductTaxAmount
  • totalShippingFeesWithoutTax / totalShippingFeesWithTax / totalShippingTaxAmount
  • totalTaxAmount

📝 Example

Illustrative header-level payload. Lines are not included; logistics shown here are indicative.

{
  "id": "CO-100045",
  "reference": "REF-2025-001",
  "createdAt": "2025-10-30T08:30:00Z",
  "updatedAt": "2025-10-30T09:12:45Z",
  "validatedAt": "2025-10-30T09:15:00Z",
	"lastSyncAt": "2025-10-30T09:14:30Z",

  "customerAccountSnapshot": {
    "externalId": "EXT-ACC-901",
    "id": "ACC-901",
    "name": "Acme Corp FR",
    "vatNumber": "FR12345678901"
  },
  "customerUserSnapshot": {
    "civility": "MR",
    "email": "[email protected]",
    "externalId": "EXT-USR-77",
    "firstName": "Alex",
    "id": "USR-77",
    "lastName": "Martin",
    "phone": "+33-1-23-45-67-89"
  },

  "productCount": 12,
  "lineCount": 9,

  "orderLogisticPrices": {
    "currency": "EUR",
    "totalPriceWithTax": 244.76,
    "totalPriceWithoutTax": 204.80,
    "totalProductTaxAmount": 39.96,
    "totalProductWithTax": 239.76,
    "totalProductWithoutTax": 199.80,
    "totalShippingFeesWithTax": 5.00,
    "totalShippingFeesWithoutTax": 5.00,
    "totalShippingTaxAmount": 0.00,
    "totalTaxAmount": 39.96
  },

  "orderLogistics": [
    { "id": "LO-001", "status": "CREATED" },
    { "id": "LO-002", "status": "CREATED" }
  ]
}

🔒 Editability reminder

  • All field changes (addresses, references, lines) happen while the order is DRAFT.
  • After placement, the Commercial Order becomes immutable; progress is reflected by Logistic Orders.

🔗 API quicklinks



Did this page help you?