Salla & Zid · Order integration architecture

Salla and Zid order statuses: build a canonical state machine

A provider-aware order state model that preserves platform facts while giving ERP, warehouse and support systems safe shared decisions.

TOPIC HUBE-commerce Engineering
Original technical illustration of Salla and Zid status events entering a canonical order state machine with separate payment, fulfilment and return tracks; not a production dashboard.
An editorial interpretation of the topic, followed by a practical execution diagram.

Salla and Zid order statuses should be treated as provider facts, not as your ERP workflow. A reliable integration keeps the platform's original status and custom sub-status, maps them to a small canonical state machine, tracks payment, fulfilment and returns on separate axes, and reconciles webhooks with API reads. This prevents a late event, renamed custom status or unsupported backward transition from moving an order to the wrong operational stage. It is useful for OMS, ERP, warehouse, shipping and customer-support integrations that must connect stores on both platforms without erasing platform-specific meaning.

No strong, recent Saudi technology announcement with enough primary technical detail was found for this slot, so this is a practical explainer rather than news. It uses the official Salla and Zid documentation verified on 18 October 2026. The design and examples are illustrative; they do not claim production results for any merchant.

Start with the documented platform contracts

Salla's List Order Statuses endpoint returns original statuses and store-specific custom statuses or sub-statuses. The documented response includes fields such as id, name, type, slug, original and children. Salla's Update Order Status endpoint accepts either a predefined slug or a custom status_id, so the write contract is not just a translated label. The platform also exposes an order history endpoint that returns previous and current statuses for a particular order.

Zid documents a fixed set of main order codes on Change Order Status, including new, preparing, ready, indelivery, delivered, cancelled and reverse-related states. The same endpoint accepts a custom status code and documents a shipping constraint: an order handled by an integrated shipping company cannot simply move from Ready back to New. Moving to Ready may also require an inventory address so the carrier knows the pickup point.

Zid additionally provides List Custom Order Statuses. Its bulk create/update endpoint is documented as a full replacement operation for custom sub-statuses. That detail matters: treating it as a partial patch can unintentionally remove statuses that another workflow still needs.

The practical conclusion is that status names are presentation. Provider code, provider ID, parent status, store ID and the observed platform version are the integration evidence.

Model four axes instead of one giant enum

One linear enum cannot represent every operational fact without inventing impossible transitions. Keep at least four related but separate axes:

| Axis | Example values | Authority | | --- | --- | --- | | Order lifecycle | open, processing, fulfilled, cancelled, closed | Salla or Zid order status | | Payment | pending, authorized, paid, refunded, voided, unknown | payment event and transaction data | | Fulfilment | unallocated, picking, packed, handed_over, delivered, exception | warehouse and shipment evidence | | Reverse flow | none, requested, approved, received, refunded, rejected | return or reverse-order workflow |

A paid order can still be preparing. A delivered order can later enter a reverse flow. A cancelled order is not automatically refunded. Zid's webhook documentation explicitly separates order.status.update from order.payment_status.update, and notes that its unpaid grouping can cover pending, refunded and voided payment states. Salla likewise publishes distinct order.status.updated, order.payment.updated, order.cancelled and order.refunded events. Those event boundaries are a strong signal not to collapse payment and fulfilment into one field.

Use one canonical lifecycle only for decisions shared across systems. Keep provider-specific details beside it, not inside an unbounded global enum.

Build a versioned mapping per store

The mapping belongs to the store connection because merchants can create, rename, deactivate and reorder custom statuses. A safe record might contain:

~~~json { "provider": "salla", "store_id": "store_42", "provider_status_id": "1638621685", "provider_slug": "completed", "parent_code": "completed", "canonical_state": "fulfilled", "mapping_version": 7, "observed_at": "2026-10-18T16:40:00Z", "source": "status_catalog" } ~~~

Use immutable mapping versions. Every order transition should record the mapping version that produced it. When a merchant changes the catalog, refresh statuses, compute a diff and require review for a changed parent or canonical state. A label-only change can be accepted automatically; a custom status moving from preparing to cancelled cannot.

Do not map unknown values to the nearest familiar state. Store them as unmapped, keep the raw payload, stop destructive automation and create an operational task. Unknown is safer than falsely delivered, refunded or cancelled.

Preserve provider facts, map through a versioned policy, and update independent order axes before ERP actions.
Preserve provider facts, map through a versioned policy, and update independent order axes before ERP actions. Open for a larger view

Treat webhooks as notifications, not an ordered log

Salla documents retries when a webhook does not receive a successful response, so duplicate delivery is expected. Zid offers order status and payment status webhooks, including conditional subscriptions for selected status, delivery option or payment method. Neither integration should assume arrival order equals business order.

Put every verified webhook into a durable inbox before processing. The deduplication key should prefer a provider event ID when available; otherwise derive a stable hash from provider, store, event type, resource ID, provider timestamp and normalized payload. Acknowledge quickly, then process asynchronously.

For each event:

1. Verify the provider signature or configured authentication. 2. Persist the raw event and receipt time. 3. Load the current order projection and mapping version. 4. Reject impossible backward transitions unless the provider's documented workflow allows them. 5. Apply the event to the correct axis. 6. Record the transition, source and correlation ID. 7. Queue a read-after-write or reconciliation check when the outcome is material.

Timestamp comparison alone is insufficient. Provider clocks, retry delays and custom-status edits can disagree. Use API state as the current platform authority and event history as evidence of how the projection changed.

For durable webhook patterns, see Salla and Zid webhooks that survive missed events.

Put a transition guard in front of every write

An ERP request to mark an order shipped should not call the provider endpoint directly. First resolve the store, current provider status, desired canonical transition, provider-specific target and required context. Then validate that the transition is allowed.

The command path should be explicit:

~~~text ERP command -> load store policy and current platform order -> resolve canonical transition -> select provider target status or custom status ID -> validate payment, inventory address and shipment preconditions -> send one idempotent command -> record an unknown outcome on timeout -> reread platform state before retrying ~~~

The idempotency key can combine store, order, desired provider status and the business command ID. On a timeout, do not blindly resend. Read the order first; the provider may have committed the transition even though the response was lost.

Separate permission failures from invalid transitions. A 401 belongs to credential handling, a 403 to scope or merchant permission, a validation response to command data, and a timeout to outcome reconciliation. Putting every failure into the same retry queue creates duplicate side effects and hides configuration errors.

Reconcile from snapshots and history

Webhooks reduce latency but cannot prove completeness. Run a bounded reconciliation loop for recently changed orders and operationally important non-terminal states. Fetch current orders with the provider's documented filters, then compare provider facts against your projection.

For Salla, order history can help explain a surprising current state. For Zid, the current order and status catalog establish the observable contract. Reconciliation should repair projections, not replay every business side effect. If a missed event reveals that an order is delivered, update the projection and evaluate downstream actions through idempotent business records; do not send a customer notification merely because the reconciler saw a different value.

Use a high-water mark plus an overlap window rather than only last_updated > cursor. The overlap catches equal timestamps and delayed visibility. Deduplicate results by provider order ID and observed version. Track reconciliation lag, mismatches, unknown statuses and repair outcomes per store.

Payment reconciliation needs a ledger rather than a status overwrite; the related design is covered in Salla payment reconciliation. Shipment transitions should similarly remain separate from the order projection; see Salla shipment state machines.

Control custom-status changes like schema migrations

Custom status catalogs are configuration schemas. Export the current catalog, calculate the desired diff and identify every automation, report, notification and role that refers to each status. Never use the translated name as a foreign key.

For Salla, preserve numeric status IDs and slugs, and keep the original parent relation. For Zid, treat the documented bulk create/update operation as full replacement: include every status that must remain, validate ownership of supplied IDs and compare the returned catalog after the write.

Roll out changes to a test store or low-risk merchant workflow first. Freeze status-catalog writes while a migration runs, or use an optimistic version check so two control planes cannot replace each other's changes. Keep the previous complete catalog and mapping version for rollback.

Decide where the canonical model should not lead

The canonical model is valuable for cross-platform analytics, warehouse queues, ERP orchestration and support views. It should not override platform-native rules. Salla and Zid remain the authority for transitions their checkout, shipping or return systems enforce.

Do not use the canonical state to fabricate provider transitions that the platform does not support. Do not rename custom statuses merely to make two stores look identical. Do not mark refunded because an order was cancelled, or delivered because a carrier printed a label. Preserve each fact at its source boundary.

For a single store with no external OMS, a complex normalization layer may be unnecessary. A durable inbox plus direct provider codes and a small reporting translation can be enough. Add the canonical model when multiple systems need shared decisions, not because architecture diagrams look cleaner.

Observe the integration as a control plane

Measure webhook age, duplicate rate, status-catalog drift, unmapped status count, invalid transition attempts, write outcome unknown, reconciliation mismatch and repair latency. Create an audit record with actor, command ID, old and new provider facts, canonical transition, mapping version and source.

Alert when a terminal provider state maps back to an active ERP queue, when payment and order axes conflict, when a custom status disappears, or when one store accumulates unknown values. Dashboards should distinguish provider state, canonical state and last verified time so support staff do not treat a stale projection as live truth.

Production checklist

Discover the status catalog per store. Persist provider IDs, codes, parents and labels. Use versioned mappings and quarantine unknown values. Separate order, payment, fulfilment and reverse flows. Store webhooks durably and make consumers idempotent. Guard writes with current-state and provider-precondition checks. Reread after unknown outcomes. Reconcile recent non-terminal orders with an overlap window. Treat custom-status replacement as a schema migration. Audit every transition and test rollback.

The goal is not to force Salla and Zid into one vocabulary. It is to let an ERP or OMS make safe shared decisions while preserving the exact platform facts needed to explain, recover and continue each order.

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