Developer Tutorial: Safe Order Updates in UltraCart REST API (Preventing Order Record Corruption)
Introduction
This guide documents a real-world support case where an order update call unintentionally “nuked” fields and left an order unviewable in the UltraCart UI due to an update performed with an incomplete expansion. It provides developer-safe guidelines for using update APIs on live orders, along with a recommended test-first procedure to protect real customer order records.
Warning: Order update calls are high-risk. If you update an order using a “smaller” object (missing fields due to limited expansion), you can unintentionally overwrite/drop data.
What happened (sanitized case summary)
A developer built a script to append merchant notes onto orders via the Order API. During testing on a real order, the script performed an update in a way that caused the stored order JSON to become inconsistent enough that the order could no longer be opened in the UltraCart UI.
Support identified the underlying issue:
The developer read the order using one set of expansion fields, but updated the order without using the same expansion
As a result, the update operation sent a partial order representation, which can lead to data loss when persisted
Support recommended using the exact same expansion for both GET and UPDATE, and verifying SDK parameter naming (
_expandvsexpanddepending on the language SDK)
UltraCart’s Order API supports returning different “sizes” of an order via the _expand parameter, and encourages limiting expansions for performance.
That performance feature is also what makes update calls dangerous if you don’t keep your GET/UPDATE expansions consistent.
Why updates can corrupt or “nuke” order data
Expansion controls what fields you have in-hand
UltraCart Order API responses may be partial unless you request expansions.
Many “update” patterns are read-modify-write
A typical script does:
GET /order/{orderId}?_expand=...Modify a field (e.g.,
merchant_notes)PUT /order/{orderId}?_expand=...(or SDK equivalent)
If step (3) uses no expansion or a different expansion, you can accidentally send an order object missing fields that existed on the server—risking overwrites, dropped nested structures, or inconsistent stored state.
Developer-safe rules for updating real orders
1) Always use the same expansion for GET and UPDATE
Declare one variable and reuse it everywhere.
Prerequisite: Confirm whether your SDK uses
expandor_expand. Some language SDKs differ.
Example (pattern-only; field names vary by SDK):
EXPAND = "items,billing,shipping,properties,payment" # example only
order = api.get_order(order_id, _expand=EXPAND)
# Modify ONLY what you intend to change
order.merchant_notes = (order.merchant_notes or "") + "\nTechnician update: ..."
api.update_order(order_id, order, _expand=EXPAND)2) Prefer SDK objects over manual JSON string building
Don’t hand-assemble JSON strings for nested order structures unless you absolutely must.
SDK models reduce malformed payloads
They also help ensure types/structure are consistent with the API spec
3) Minimize your changes (surgical updates)
Only change the fields you intend to change.
Best practices:
Avoid rewriting large sections of the order object “just because it’s present”
Do not “rebuild” the order from scratch
Treat update code as sensitive migration code, not casual scripting
4) Add validation + logging before sending updates
At minimum:
Validate the final payload is valid JSON (if you’re serializing)
Log the outbound request (redact credentials + PII)
Log the response status and body
Keep a “replay log” so you can reconstruct what changed
5) Use a dry-run mode
Build the updated order payload, but don’t send it unless explicitly enabled.
python update_order_notes.py ORDER_ID "Message here" --dry-run
python update_order_notes.py ORDER_ID "Message here" --commit6) Implement guardrails for “real” orders
Recommended guards:
Block updates unless the order matches an allowed test prefix/tag
Block updates on orders with a shipment/refund state (unless your use case requires it)
Require explicit confirmation flags for production use (
--commit --i-understand-risk)
Recommended procedure (test-first workflow)
Phase 1: Test in your own developer account (preferred)
Create a dedicated developer account for integration testing.
Generate multiple sample orders covering common edge cases:
multiple items
coupons/discounts
taxes/shipping
digital + physical mix
Run your update script against these orders until stable.
Tip: A dev account removes the “real customer record” risk while you iterate quickly.
Phase 2: Test on test orders inside the merchant’s account
Create clearly labeled test orders (e.g., internal email address, internal SKUs).
Add an obvious marker in merchant notes like:
TEST ORDER — API UPDATE SCRIPT
Run the script only on those orders.
Verify in the UltraCart UI:
the order opens normally
merchant notes updated as expected
no unexpected changes occurred elsewhere
Phase 3: Controlled rollout on production orders
Enable production mode only after Phases 1–2 are complete.
Roll out with a small batch size:
1 order → 5 orders → 25 orders
Add monitoring:
error alerts
audit logs
quick rollback plan (restore from logged “before” payload if applicable)
Troubleshooting checklist
Symptom: Order becomes unviewable in the UI after update
Do this immediately:
Stop running the script.
Locate the last successful “before” snapshot (your logs).
Confirm GET/UPDATE expansions were identical.
Provide Support with:
sanitized request/response logs
your expansion string
which SDK + version you used
the minimal repro steps (no credentials)
Symptom: Fields disappear after update
Most common causes:
Update call used a smaller/no expansion than the GET call
Script serialized an incomplete object back to the API
Incorrect field naming / wrong model object
Implementation checklist (copy/paste for dev teams)
[_] Use SDK models, not manual JSON building
[_] Single
EXPANDvariable reused for GET and UPDATE[_] Verify
_expandvsexpandfor your SDK/language[_] Modify only intended fields
[_] Dry-run mode implemented
[_] Logging implemented (redacted)
[_] Tested in developer account first
[_] Tested on merchant test orders next
[_] Production rollout is gradual with monitoring