Saudi commerce · Salla · Order integration

Salla light orders: hydrate data without N+1 storms

A production architecture for replacing Salla's retired expanded order response with bounded, observable and recoverable resource hydration.

TOPIC HUBE-commerce Engineering
Tall warehouse shelving filled with organized packages, illustrating order resources that must be hydrated selectively for fulfilment and ERP workflows.
P

Salla's legacy expanded order response is no longer a safe integration assumption. The official Order Details and List Orders documentation says expanded responses stopped being supported on September 1, 2026; the light Order Details contract omits shipments, order items, pickup branch and customer groups. The production answer is to store a compact canonical order projection, hydrate only the resources each workflow actually needs, consume webhooks as change signals, and reconcile from Salla instead of rebuilding the old giant response with uncontrolled N+1 calls.

This is a practical engineering explainer, not a news report. It uses Salla's current Merchant API documentation and changelog, verified on October 26, 2026. The exact fields described as deprecated or omitted are documented facts. The storage model, queues, budgets and recovery workflow below are engineering recommendations.

The answer first

Treat the light order as the stable envelope for identity, total, status, payment summary and customer reference. Do not assume embedded items, shipments, pickup branch or customer groups will be present. Decide the data needs of each consumer, fetch missing resources through their dedicated endpoints, preserve each resource with its own freshness and source metadata, and publish a canonical internal snapshot only when the workflow's required dependencies are complete.

ConsumerRequired dataHydration policy
Customer support listidentity, status, total, customer summarylight order only
ERP invoice exportorder totals, items, payment allocationorder plus List Order Items; validate payment_methods
Fulfilmentitems, shipment and pickup contexthydrate items and shipment resources
Marketing segmentcustomer groupsfetch Customer Details under a separate freshness policy
Financial reconciliationpayment methods, transactions and refundsuse payment_methods and transaction resources; do not infer from one label

The goal is not to minimize calls at any cost. It is to make every call intentional, bounded, observable and recoverable.

What changed in the contract

Salla's Order Details documentation says the default response is light after the legacy expanded response expiry. It explicitly describes light details as excluding Shipments, Items, Pickup Branch and Customer Groups. List Orders separately documents that expanded=true is no longer supported. The changelog also records that customer groups under the customer object were deprecated and should be obtained through Customer Details.

On September 3, 2026, Salla added payment_methods arrays to create, update, duplicate, details, list and webhook order contracts. That matters because a single payment_method string cannot represent split tender accurately. Build financial logic around the array when present and keep the single label only as a compatibility summary.

Documentation examples can lag the declared contract and may show fields that a specific response shape does not guarantee. Generate tests from the fields your app requires, then test a demo store and production-like fixtures. Presence in one example is evidence for a sample, not a permanent guarantee.

Model the order as resources, not one document

A monolithic local order row makes missing embedded objects look like data loss. Use a resource-oriented projection instead:

{
  "store_id": "trusted-installation-id",
  "order_id": "1333249299",
  "reference_id": "275839672",
  "order_version": 42,
  "order_fetched_at": "2026-10-26T17:20:00Z",
  "items_state": "fresh",
  "items_fetched_at": "2026-10-26T17:20:01Z",
  "shipments_state": "not_required",
  "customer_groups_state": "stale",
  "payment_state": "fresh",
  "source_event_id": "durable-inbox-id"
}

Keep order core, items, shipments, customer profile and payment transactions in separate tables or versioned records. Each record needs source identity, observed time, content digest and last successful fetch. Null means a documented null. Missing means not returned. Not requested means the workflow did not need it. Failed means hydration was attempted but did not complete. Those states must not collapse into the same database value.

Original engineering diagram: durable ingestion, a light order envelope, selective resource hydration, canonical publication and reconciliation. Photo by Nenad Stojković (Shixart1985), CC BY 2.0 via Wikimedia Commons; resized/cropped for responsive presentation.
Original engineering diagram: durable ingestion, a light order envelope, selective resource hydration, canonical publication and reconciliation. Photo by Nenad Stojković (Shixart1985), CC BY 2.0 via Wikimedia Commons; resized/cropped for responsive presentation. Open for a larger view

Define hydration profiles before code

Create named profiles tied to business actions:

ProfileResourcesDeadlineFailure policy
support-listorder coreinteractiveshow last known state with freshness
fulfilment-readycore, items, shipmentsnear-real-timeblock warehouse command until complete
accounting-exportcore, items, payment allocationsbatchretry, then quarantine the order from the export
customer-segmentationcustomer details and groupsbackgroundallow stale cache within policy

The API client accepts a profile, not a collection of booleans spread across controllers. This keeps a support page from accidentally triggering four remote requests per row and makes rate-limit planning measurable.

Build an idempotent hydration planner

When a webhook or backfill discovers an order, write an inbox record first. Upsert the light order envelope, then plan only missing or stale resources. Use a key such as store_id + order_id + resource + desired_revision so duplicate webhooks and job retries converge on the same work.

webhook/backfill
  -> durable inbox
  -> upsert light order
  -> evaluate hydration profile
  -> enqueue missing resources
  -> validate and persist each resource
  -> publish canonical projection

Do not hold the webhook HTTP request open while hydrating. Acknowledge only after the inbox is durable, then process asynchronously. Webhooks signal that state changed; they are not a complete or ordered database replication protocol. Periodic reconciliation remains necessary.

Avoid N+1 without recreating expanded

The failure mode is predictable: list 30 orders, then call details, items, shipments and customer details for each one. A single page becomes more than 100 requests, latency grows, retries amplify load and one dependency failure makes the whole screen unreliable.

Use these controls:

  • hydrate only the selected or actionable orders, not every row on a list;
  • batch work through a queue with per-store concurrency and request budgets;
  • cache immutable or slowly changing resources with explicit freshness;
  • deduplicate identical resource fetches across users and workers;
  • prioritize fulfilment and financial commands above enrichment;
  • pause enrichment when the rate-limit budget is low;
  • persist partial progress so a retry resumes instead of restarting the entire order.

Salla's List Orders guidance requires sequential pages, recommends per_page=30, warns against skipping pages and asks consumers to complete pagination within a 15-minute cached window. A reliable backfill therefore has a page checkpoint and a bounded date window. Hydration jobs should be downstream from discovery so slow resource calls do not break that sequential pagination contract.

Handle split payments as allocations

The payment_methods array can describe more than one method, amount and transaction reference. Store each entry as an allocation with a stable local identity. Do not sum floating-point strings with binary arithmetic; parse amounts into minor units or an exact decimal type and retain the currency.

{
  "order_id": "1333249299",
  "allocations": [
    {"method": "bank", "amount_minor": 1093, "reference": null},
    {"method": "credit_card", "amount_minor": 546, "reference": "9682442091042222"}
  ]
}

Validate that allocation currency matches the order currency and compare the allocation total with the authoritative paid amount used by the financial workflow. A mismatch is a reconciliation exception, not a value to silently normalize. Redact transaction references from general logs and analytics.

Treat webhooks as invalidation signals

Salla documents order webhook models and multiple event families. Route each event to a small invalidation map:

Event familyMark staleTypical action
order.products.updateditems and order totalsrefetch items and core
order.payment.updated or order.refundedpayment allocations and transactionsrefetch financial resources
order.shipping.address.updatedcore delivery projectionrefetch order details
order.shipment eventsshipment projectionrefetch affected shipment/order
order.customer.updatedcustomer projectionrefetch customer details if required

Do not assume delivery order. A newer fetch must not be overwritten by a delayed older event. Store event receive time and available platform timestamps, but decide convergence through authoritative read-back and resource version rules.

Publish an internal canonical order safely

Downstream systems should not depend directly on Salla's JSON shape. Publish a typed internal contract with explicit optionality and provenance:

{
  "order_key": "store-42:1333249299",
  "status": "in_progress",
  "currency": "SAR",
  "total_minor": 1639,
  "items": {"state": "fresh", "count": 2},
  "shipments": {"state": "not_required"},
  "payments": {"state": "fresh", "allocated_minor": 1639},
  "observed_at": "2026-10-26T17:20:01Z"
}

Version this schema. Keep raw source snapshots privately for diagnosis, but do not expose them as the domain contract. When a required resource is incomplete, publish a typed incomplete state or withhold the action-specific projection; never fabricate an empty items array that downstream interprets as a cancelled order.

Reconcile, do not trust continuous delivery

Run reconciliation over recently changed orders and business-critical states. Compare the current Salla core, item identities and quantities, shipment references and payment allocations with local projections. Record the difference before repair, apply an idempotent update and verify convergence.

Prioritize:

  • paid orders missing item hydration;
  • fulfilment-ready orders without a shipment projection;
  • refunds whose payment allocation is stale;
  • webhook events with failed or dead-lettered hydration;
  • orders whose resource freshness exceeds the workflow SLA.

Use a bounded lookback and page checkpoints. Do not rescan the entire store every few minutes.

Best practices

  • Code to the declared light contract, not a rich sample response.
  • Separate resource absence from null, not requested and fetch failure.
  • Use named hydration profiles tied to business actions.
  • Keep webhook ingestion fast and durable; hydrate asynchronously.
  • Enforce per-store concurrency and request budgets.
  • Store payment allocations exactly and reconcile their totals.
  • Version the canonical internal schema and preserve provenance.
  • Test old and new fixtures during the migration window.

Anti-patterns

  • Sending expanded=true and assuming ignored parameters still work.
  • Fetching details, items, shipments and customer data for every list row.
  • Treating a missing embedded array as an empty business fact.
  • Using one payment_method string for split-payment accounting.
  • Rebuilding the entire order synchronously inside a webhook request.
  • Letting a delayed event overwrite a newer authoritative fetch.
  • Logging complete customer and transaction payloads for convenience.

Migration checklist

  1. Inventory every field currently read from List Orders, Order Details and webhooks.
  2. Classify each field as core or owned by a dedicated resource.
  3. Add explicit resource state and freshness columns.
  4. Introduce hydration profiles and a durable work queue.
  5. Parse payment_methods as exact allocations.
  6. Run contract fixtures for missing and null objects.
  7. Shadow the light pipeline and compare canonical outputs.
  8. Move consumers one workflow at a time.
  9. Remove expanded=true and alert on accidental use.
  10. Reconcile recent orders and verify no action used incomplete data.

Related reading: Salla order backfills, Salla and Zid order status state machine, Salla webhook endpoint rotation, the E-commerce Engineering hub, and Salla & Zid integration services.

Primary references

Official references

These references document the tools discussed. Examples and design decisions are illustrative and should be adapted to the project and its versions.

Prepared by: Noor Yasser

FROM DECISION TO DELIVERY

Working through a similar engineering challenge?

I help teams turn architecture decisions into a clear scope and dependable, reviewable implementation.

Book a 30-minute callRelated serviceBackend engineering & API integrationsRelevant projectLogistics at scale