Synchronize a Draft Order
Introduction
A commercial order in DRAFT status is editable and evolves until placement. Between the moment it is created and the moment it is placed, catalog data can change: prices may be updated, stock levels may decrease, products may become inactive, or quantity rules may evolve.
The sync endpoint reconciles a draft order with the current state of the DJUST catalog and returns a detailed list of warnings - either blocking (the order cannot be updated) or informational (the order was updated, but differences were detected).
When to sync
Synchronization is not limited to a pre-placement check. It should be called whenever the order needs to reflect the latest catalog reality:
- On order display - When a buyer reopens a draft order, call sync to refresh prices, stock, and availability before rendering the page. This ensures the buyer always sees accurate, up-to-date information.
- After a period of inactivity - If a draft order has been idle for hours or days, catalog data may have drifted significantly.
- Before placement - As a final validation step before calling the placement endpoint (ORDER-212), to catch any last-minute changes.
- After editing lines - When lines have been added or quantities changed, sync ensures the full order remains coherent.
Tip: Synchronization works with DJUST as the single source of truth (standard mode). No external pricing or stock system is required.
Key Concepts
Standard Mode
In standard mode, synchronization relies exclusively on data persisted in DJUST:
- Catalog: product and variant activation status, catalog view eligibility for the buyer's context
- Offer prices: price values, eligibility per account or account group
- Stock / availability: offer inventory levels
- Quantity rules: minimum, maximum, item per pack
- Custom fields: offer-level and order-level custom field validity
No external real-time pricing (RTP) source is involved. Everything described on this page applies to the standard mode; tenants running Real-Time Pricing differ on several points, gathered in Real-Time Pricing tenants.
What Gets Rewritten, and From Where
Every value written on a synchronized line comes from the offer price the line already points to, and from its offer, product variant and product:
| Data rewritten on the line | Source |
|---|---|
| Unit price (the price tier matching the line quantity, discounted price when one is set) and item per pack | Offer price |
| Currency, packing type, quantity per item, minimum and maximum order quantities | Offer |
| Product and shipping tax rates and codes | Offer custom fields carrying the tax roles |
| Amounts excluding and including taxes, tax amounts and totals | Recomputed with the tax calculation mode and rounding of the logistic order |
| Product snapshot: SKU, external ID, names, descriptions, brand, unit, tags, attributes, classification category and finest navigation category | Product |
| Variant snapshot: SKU, external ID, names, descriptions, EAN, MPN and attributes | Product variant |
| Offer custom field snapshot | Active custom fields of the offer |
On the order itself, the sync writes the synchronization timestamp; on each logistic order, the totals, the line count and the product count are recomputed from its lines. Shipping fees are recomputed only when the shipping matrix is active.
What Is Never Changed
- The set of lines — no line is added or removed, and each line keeps its offer price, even when another price now applies to the account.
- The line quantity.
- The line custom fields — their values are kept as they are, including the value of a custom field deactivated since.
- The order status, the customer user and customer account snapshots, the supplier and the addresses.
Note: Since 3.139, the standard mode no longer rewrites the line custom fields with their own values. A line carrying a deactivated custom field is therefore synchronized without raising any warning for it.
Catalog View Eligibility
Each order line is verified against the catalog views assigned to the customer user. If a product has been removed from a catalog view, or if the buyer's catalog view scope has changed, the product is flagged with a blocking warning (F-W-015).
This same eligibility check is also enforced when adding a product to an order (add-to-cart). A product that is not visible in the buyer's current catalog view context cannot be added to a commercial order.
Warning: A product that was previously valid may become ineligible after a catalog view configuration change. Always call sync before placement to catch these cases.
Blocking vs. Informational Warnings
Each warning returned by the sync endpoint carries a blocked flag:
| Type | blocked | Behavior |
|---|---|---|
| Blocking | true | The line is left untouched: not corrected, not deleted, not partially written. The other lines of the same order are synchronized normally. |
| Informational | false | The line is updated. Warnings notify the caller about changes that were automatically applied (e.g. price update, quantity adjustment). |
Warning: A blocking warning stops the synchronization of its own line only. The call fails with a400solely when no line survives — see Error handling.
Warning Structure
Each warning in the response array contains:
{
"id": "OFFP-EXT-00042",
"code": "F-W-018",
"blocked": true,
"detail": "Requested quantity is lower than the minimum order quantity.",
"changes": [
{
"field": "quantity",
"previousValue": "2",
"newValue": "5"
}
]
}| Field | Description |
|---|---|
id | External identifier of the offer price concerned |
code | Warning code (see Error / Warning codes) |
blocked | true if blocking, false if informational |
detail | Human-readable description of the issue |
changes | (optional) Array of before/after value differences. Each entry contains field (string), previousValue (string), and newValue (string). Present only when a meaningful value comparison applies. Absent for existence, activation, or eligibility warnings. |
How to read changes depending on the warning type:
- Informational (
blocked: false):previousValueis the old value on the order line,newValueis the new value that was applied by the sync. - Blocking (
blocked: true):previousValueis the current value on the order line,newValueis the constraint or limit that the line violates (e.g. the minimum order quantity). No change is applied.
Preconditions
Before calling the sync endpoint, ensure:
- The commercial order has not been validated (
validatedAtmust be empty) - The order is in a modifiable state (DRAFT)
- The order was created in an Order-based Checkout context
- The caller is either the order owner or has the required permissions to edit order lines
If any precondition is not met, the sync is rejected with an error response (see Error handling).
API Reference
Endpoint
PUT /v1/shop/commercial-orders/{commercialOrderId}/syncoperationId: ORDER-223
Path Parameters
| Parameter | Type | Description |
|---|---|---|
commercialOrderId | string | Commercial order identifier (REFERENCE) |
Headers
| Header | Required | Description |
|---|---|---|
dj-client | Yes | Must be ACCOUNT |
dj-api-key | Yes | API key |
dj-store | No | Store context |
dj-store-view | No | Store view context |
Warning: Onlydj-client: ACCOUNTis accepted on this endpoint.
Request Body
No request body. The sync applies to all existing lines on the order.
Response
200 OK - Returns an array of warnings (may be empty if everything is up to date):
[
{
"id": "OFFP-EXT-00042",
"code": "F-W-014",
"blocked": true,
"detail": "The product variant with id PV-00042 is inactive."
},
{
"id": "OFFP-EXT-00099",
"code": "F-W-018",
"blocked": true,
"detail": "Requested quantity is lower than the minimum order quantity.",
"changes": [
{
"field": "quantity",
"previousValue": "2",
"newValue": "5"
}
]
},
{
"id": "OFFP-EXT-00110",
"code": "F-W-026",
"blocked": false,
"detail": "Unit price has been updated.",
"changes": [
{
"field": "unitPrice",
"previousValue": "12.50",
"newValue": "13.20"
}
]
}
]When the response contains only non-blocking warnings (or no warnings at all), the order has been updated successfully. The lastSyncAt timestamp is set on the order.
Note: The warnings report a subset of what changes, not all of it. Every other price field (amounts excluding taxes, tax amounts, totals, packing information, order quantity bounds) and every snapshot is recalculated without any warning. An empty response therefore does not mean that nothing changed — read the lines back with ORDER-561 when you need the resulting values.
What Gets Checked
Blocking Warnings (blocked: true)
blocked: true)The following conditions prevent the line from being updated. The line is left exactly as it was, while the other lines of the order are synchronized normally.
Product / Variant
| Code | Condition | changes |
|---|---|---|
F-W-001 | The variant referenced in the order line does not exist | No |
F-W-014 | The variant exists but is INACTIVE | No |
F-W-014 | The parent product is INACTIVE | No |
F-W-015 | The product is not eligible in the current catalog view context | No |
Offer / Pricing
| Code | Condition | changes |
|---|---|---|
F-W-001 | The offer price does not exist | No |
F-W-014 | The offer price is INACTIVE | No |
F-W-001 | The offer inventory does not exist | No |
F-W-014 | The offer inventory is INACTIVE | No |
F-W-015 | The offer price is not eligible for this account | No |
F-W-016 | The offer price does not match the variant on the order line | No |
F-W-014 | The supplier owning the offer is INACTIVE | No |
Quantity Rules
| Code | Condition | changes |
|---|---|---|
F-W-017 | Quantity < 0 | Yes - quantity: requested value vs 0 |
F-W-018 | Quantity < minimum order quantity | Yes - quantity: requested value vs minOrderQuantity |
F-W-019 | Quantity > maximum order quantity | Yes - quantity: requested value vs maxOrderQuantity |
F-W-020 | Quantity is not a multiple of item per pack | Yes - quantity: requested value vs itemPerPack |
F-W-021 | Zero quantity is not allowed for this line | No |
Zero quantity behaviorDuring synchronization, an order line whose quantity becomes
0is removed by default and warningF-W-021is raised. This behavior can be overridden at tenant level with theCART_LINES_0_QUANTITY_AUTHORIZEDfeature flag — when enabled, order lines with a quantity of0are accepted and kept in the synchronized order; only negative quantities (F-W-017) are rejected. Contact your CSM to enable this flag on your tenant.
Stock
| Code | Condition | changes |
|---|---|---|
F-W-022 | Not enough stock available for the requested quantity | Yes - quantity: requested value vs available stock |
Custom Fields
| Code | Condition | changes |
|---|---|---|
F-W-023 | Offer custom field configuration is missing or no longer valid | No |
F-W-024 | Offer custom field value is invalid | No |
F-W-025 | Required custom field value is missing at offer or order level | No |
Note: At order line level,F-W-025is not blocking — see below.
Informational Warnings (blocked: false)
blocked: false)The following changes are applied automatically and reported for traceability. The changes field provides the before/after values for each applied change.
Important: Informational warnings reflect a diff between the order line and the current catalog state. Once the sync applies the changes, calling sync again immediately will not return these warnings because the order is now in sync with the catalog. This is expected behavior - it means the order is up to date.
| Code | Change applied | changes |
|---|---|---|
F-W-026 | Unit price has been updated | unitPrice: old price vs new price |
F-W-027 | Currency has been updated | currency: old currency vs new currency |
F-W-028 | Tax values have been updated | taxRate, taxCode, shippingTaxRate, shippingTaxCode (one entry per change) |
F-W-029 | Quantity has been automatically adjusted (Real-Time Pricing only) | quantity: old quantity vs adjusted quantity |
F-W-030 | Custom field values have been resynchronized — never the line custom fields in standard mode | One entry per custom field changed (field = custom field key) |
F-W-025 | An active and mandatory line custom field has no value. The line is synchronized anyway and its custom fields are left unchanged. | No |
A change of the shipping fees of a logistic order is also reported with F-W-026, with the logistic order as id.
For the full warning code reference, see Error / Warning codes.
Real-Time Pricing tenants
Everything above describes the standard mode. When the tenant runs with Real-Time Pricing (RTP), the lines are sent to an external pricing system and its answer replaces the catalog data on the following points:
| Point | Behavior under Real-Time Pricing |
|---|---|
| Set of lines | Comes from the pricing system: a line may be added (F-W-031) or removed (F-W-032). Logistic orders left without any line are deleted. |
| Quantity | Comes from the pricing system; a change is reported with F-W-029. |
| Prices and stock | Come from the pricing system instead of the offer price. |
| Line custom fields | The values returned by the pricing system overwrite the stored ones, without any warning. The custom fields it does not return are kept. An invalid value is reported with F-W-025. |
| Quantity rules | Minimum, maximum and pack constraints are not enforced. |
| Status and eligibility checks | Offer, offer stock, product and supplier status, and account eligibility are not checked. Catalog view visibility still applies. |
Warning: The handling of line custom fields is the main difference between the two modes. In standard mode they are never rewritten; under Real-Time Pricing they are replaced by whatever the pricing system returns.
Typical Workflow
flowchart LR
%% Styles (Readme)
classDef create fill:#e8f1ff,stroke:#2f6feb,stroke-width:2px,color:#0b3d91;
classDef read fill:#ede9fe,stroke:#7c3aed,stroke-width:2px,color:#1e1b4b;
classDef update fill:#e0f7fa,stroke:#06b6d4,stroke-width:2px,color:#0c4a6e;
classDef decision fill:#fff4e5,stroke:#f59e0b,stroke-width:2px,color:#7a3e00;
classDef place fill:#dcfce7,stroke:#16a34a,stroke-width:2px,color:#14532d;
classDef stop fill:#fee2e2,stroke:#ef4444,stroke-width:2px,color:#7f1d1d;
A[📘 Buyer opens<br>draft order] --> B[🔄 Call sync<br>ORDER-223]
B --> C{Blocking<br>warnings}
C -->|None| D[✅ Order updated<br>lastSyncAt set]
D --> E{Buyer<br>action}
E -->|Continue editing| A
E -->|Place order| F[➡️ ORDER-212]
C -->|At least one| G[⛔ Flagged lines<br>left untouched]
G --> H[🔧 Remove or fix<br>affected lines]
H --> B
A:::create
B:::update
C:::decision
D:::place
E:::decision
F:::place
G:::stop
H:::update
Recommended integration patterns
Pattern 1 - Sync on order display (recommended)
Call sync every time the buyer opens or returns to the draft order view. This keeps prices and availability up to date and allows the UI to display warnings immediately.
- Buyer navigates to the draft order view
- Call sync (
ORDER-223) - Render the order with fresh data and display any warnings to the buyer
- Buyer edits lines if needed → re-sync after edits
- When ready → place order (
ORDER-212)
Pattern 2 - Sync before placement only
Call sync as a final validation step just before placing the order. Simpler to implement, but the buyer may discover stale data only at checkout time.
- Build your draft order (create, add lines, set addresses)
- Call sync (
ORDER-223) before placement - If blocking warnings → display issues, fix lines, retry sync
- If no blocking warnings → proceed to placement (
ORDER-212)
Tip: Sync does not add or remove lines - it only validates and updates existing ones. To remove problematic lines, use the line deletion endpoint (ORDER-350) before retrying sync.
Error Handling
No line could be applied
When no line survives validation, nothing is written and the call returns a 400. The error code now tells apart the two most frequent causes, so a buyer can be shown the right message instead of a generic one:
| Code | Returned when |
|---|---|
OR0038 | No line was applied and every blocking warning concerns the available stock (F_W_022) |
OR0039 | No line was applied and every blocking warning concerns the packing of the offer (F_W_020) |
OR0034 | Any other case: mixed causes, another reason, or an empty line list. Unchanged. |
The detail field keeps its current format in all three cases, and the general behaviour is unchanged: when no line survives validation, nothing is written.
Warning: Action required — an integration that testsOR0034today to detect a stock or a packing problem must now handleOR0038andOR0039as well.
The same three codes apply to ORDER-150 (PUT /v2/shop/commercial-orders/{commercialOrderId}/lines) — see Working with Draft Orders.
Other errors
| HTTP | Code | Message |
|---|---|---|
| 400 | F-E-012 | Invalid string value for commercialOrderId. Expected a REFERENCE identifier. |
| 401 | F-E-032 | Unauthorized. Missing or invalid authentication token. |
| 403 | F-E-030 | Caller is not allowed to synchronise this commercial order. |
| 404 | F-E-002 | Commercial order not found for the provided commercialOrderId. |
| 409 | F-E-028 | Commercial order must not be in status VALIDATED to perform this operation. |
| 422 | F-E-039 | No eligible order lines could be processed for synchronisation. |
For the full error reference, see Error / Warning codes.
Best Practices
- Sync on every order display - Call sync whenever the buyer opens the draft order view, not just before placement. This ensures prices and stock are always accurate.
- Handle blocking warnings gracefully - Display the
detailmessage to the user and let them decide whether to fix or remove affected lines. - Use
lastSyncAtfor freshness - After a successful sync,lastSyncAtis updated on the order. You can use this to decide whether a re-sync is needed (e.g. skip sync iflastSyncAtis less than a few minutes old). - Re-sync after line edits - After adding, removing, or changing quantities on lines, call sync again to revalidate the full order.
- Understand idempotent behavior - Informational warnings only appear when there is a difference to report. A second consecutive sync call returns no informational warnings because the first call already applied the changes. This is expected - it means the order is up to date.
- Do not use sync as a create mechanism - In standard mode, sync never creates new lines. It only validates and updates existing ones.
Common Mistakes
| Mistake | Consequence | Fix |
|---|---|---|
| Calling sync on a validated order | 409 error | Only sync orders where validatedAt is empty |
Using dj-client: OPERATOR | 403 error | Use dj-client: ACCOUNT |
| Expecting sync to add new lines | Lines are not added | Sync only validates existing lines in standard mode |
| Ignoring informational warnings | Missing price or quantity changes | Always check the full warning array, even when blocked: false |
| Expecting informational warnings on a second call | No warnings returned | This is normal - the first sync applied changes, so there is no longer a diff to report |
| Using DJUST_ID in the path | 400 error | Use the REFERENCE identifier for commercialOrderId |
Parsing the detail text to tell a stock problem from a packing one | Fragile integration that breaks on any wording change | Read the error code: OR0038 for stock, OR0039 for packing, OR0034 for anything else |
Testing only OR0034 to detect a stock or packing rejection | Stock and packing rejections are no longer caught | Handle OR0038 and OR0039 too |
| Relying on sync to refresh the line custom fields in standard mode | Values stay exactly as they were, including those of a custom field deactivated since | Write the line custom fields explicitly with the order line endpoints |
| Assuming a blocking warning cancels the whole synchronization | The other lines have already been updated | Read the order back with ORDER-561 after any sync that returned warnings |
Updated 10 days ago

