Integrate an order management system

Ask about this Page
Copy for LLM
View as Markdown

Export placed Orders to an order management system, and apply status, fulfillment, shipment, cancellation, return, and Inventory updates back to commercetools.

An order management system (OMS) routes, allocates, and fulfills Orders after checkout. This guide covers the two one-way flows that connect it to commercetools: an outbound export of placed Orders, and an inbound flow that applies post-order changes to the Order and to Inventory. It also covers the scheduled reconciliation that repairs whatever those two flows miss.

This guide does not cover master data. Products, Categories, and Prices belong to Integrate product data, which also covers the initial Inventory load. B2B accounts, contract Prices, and financial documents belong to Integrate ERP. When one system is both your ERP and your OMS, apply those guides to master data and this guide to the post-order lifecycle. This guide also does not cover payment capture or refund, which belong to your payment integration. Copying Orders to a data warehouse or analytics tool for reporting is a separate one-way export covered by Integrate an analytics destination.
Carrier rate quoting during checkout belongs to Integrate a shipping carrier or rate service. That guide also covers booking labels and recording tracking numbers directly against a carrier, which applies only when no OMS is in the picture. When an OMS books shipments, this guide owns the Delivery, Parcel, and tracking write-back described in Read the Order before writing to it. Only one system may write that data, because two writers produce duplicate Deliveries and conflicting tracking numbers.
Before you start, you need a commercetools Project with Orders being created, an OMS with a documented API, and an agreed owner for each data domain described in the next section. For the wider planning framework, see Integration planning and patterns.

Define OMS integration requirements

The Connector choice and the sync design are both downstream of these decisions. Record them before you configure or build anything.

Assign a source of truth per data domain

Order data in commercetools is captured at checkout. In most implementations the system of record for the Order then lives downstream in the OMS or ERP, and commercetools becomes a read-only reflection of the fulfillment lifecycle. For organizations without an OMS or ERP, commercetools can remain the source of truth for Orders. For the wider decision, see Plan integrations.

Assign exactly one owner per domain, and make the other side read-only for it. Never synchronize the same field in both directions: a field with two writers produces conflicts, update loops, and lost changes that are difficult to diagnose after the fact.

Data domainTypical owner after checkoutDirection
Order capture and contentscommercetoolscommercetools to OMS
Order status and workflowOMSOMS to commercetools
Fulfillment and Line Item statusOMSOMS to commercetools
Shipment, Delivery, and trackingOMSOMS to commercetools
Cancellations after handoffOMSOMS to commercetools
Returns and return statusOMSOMS to commercetools
Inventory quantitiesThe system of record for OrdersUsually OMS to commercetools
Customer profileUsually commercetoolscommercetools to OMS
Inventory follows the system of record for Orders because Orders consume stock. If the OMS owns Orders, it usually owns Inventory as well. The direction for the Customer profile depends on your Customer integration, so confirm it against Integrate a CRM before you rely on the row above.

Scope the export and inbound flows

Answer and record the following questions because each one changes the design:

  • Which Orders export, and when? Every Order at creation, or only after payment or approval? An export that must wait for payment subscribes to the state change instead of Order creation, or checks the payment state inside the handler.
  • What comes back inbound? Order status, Line Item fulfillment status, shipment data including tracking, cancellations, returns, Inventory levels, or a subset.
  • How does the OMS deliver updates? A webhook it calls, an endpoint you poll, or a batch file. A webhook maps to a service application. Polling and batch files map to a job application.
  • What latency and volume must the integration support? Real-time delivery, near-real-time, or an overnight batch. Order and Inventory volume determine whether a single reconciliation run can complete inside its time budget.
  • How do identifiers map? How OMS statuses map onto commercetools state, how SKUs map to Inventory locations and supply Channels, and where the OMS identifier is stored on the Order.
  • How much drift and delay is tolerable? This sets the reconciliation schedule and the alerting thresholds.
  • Does split or partial fulfillment apply? Split shipments, partial fulfillment, and pickup in store each add Deliveries and states that the mapping must cover.

Record special requirements

The list above covers the common shape, not every implementation. Capture additional constraints as separate requirements. Each one can move the decision in the next section from configuring a Connector toward forking or building one:

  • B2B flows, including purchase order numbers, approval steps, and Business Unit ownership.
  • Marketplace or multi-vendor fulfillment split across sellers. The OMS owns Delivery, Parcel, and tracking; a marketplace integration forwards that status to each seller and must not write it. See Integrate a marketplace service.
  • Returns and return merchandise authorization workflows owned by a separate system.
  • Recurring Orders and subscription flows.
  • Multi-Store, multi-market, or multi-currency routing.
  • An existing OMS contract, account, or tenant that constrains the integration shape.
  • Custom Order workflows modeled as States.
  • Data residency and compliance constraints that restrict the deployment Region.

Choose an integration path

Work through these options in order and stop at the first one that meets your requirements. Each later option is more to build and more to maintain.

Check for an existing OMS Connector

Check the current Connector inventory instead of relying on a remembered list, because published Connectors and their versions change. Use an API Client with the view_connectors scope to call the Search Connectors endpoint and filter by integration type:
Search for OMS Connectorshttp
GET https://connect.{region}.commercetools.com/connectors/search?integrationTypes=oms&integrationTypes=shipping
Query both oms and shipping to find relevant candidates. The IntegrationType enum has no separate fulfillment value. For the host to use in each Region, see Hosts and authorization. The same search is available in the Merchant Center.
Compare certification and access, source availability, installation requirements, and Region support using the canonical Connector representation. Record the Connector key and version you evaluated.
A listing in the technology partner directory is not automatically an installable Connector. For installable Public Connectors, use Connect in the Merchant Center. Confirm the deployment model of each candidate before you plan a Connect deployment. The vendor documentation and repository are authoritative for how an integration installs and what it covers.

Compare each candidate against your requirements rather than against its headline. Check the flows it implements, its direction and ownership model, available mapping configuration, split shipment and return handling, and support for your Region and volume.

Prove that a gap is not configuration

When a Connector matches your OMS but appears to be missing a behavior, confirm that configuration cannot close the gap before you consider forking it. Inspect message selection, field mappings, state mappings, and enabled flows before you decide that implementation work is required.

Fork or build

If a Connector matches your OMS and has a genuine gap that configuration cannot close, and its source is available, fork it. Add only the difference and deploy the result as an Organization Connector. You keep the working sync scaffolding and maintain a smaller change.

If no Connector matches your OMS, or the OMS is bespoke, build a new one. Decide where the integration runs before you scaffold it; for a comparison of vendor middleware, integration platforms, cloud services, and Connect, see Compare middleware and runtime options. The Connect CLI ships a fulfilment-integration template that scaffolds the application structure for these flows:
Initialize a fulfillment Connectorbash
commercetools connect init my-oms-connector --template fulfilment-integration
The template is not listed on the Application templates overview, which documents the payment, product export, tax, and email templates. It declares four applications: an order-export event application, an order-updates service application, an inventory-import service application, and a product-export event application. Keep the applications your requirements call for and remove the rest. If you need scheduled reconciliation, add a job application, which the template does not include.
The fulfilment-integration template supplies application structure, not a working OMS integration. This assessment covers commit 30ce085, inspected on 28 August 2026. Before production use, implement the following:
  • The OMS calls themselves. The export handlers map an Order into a local object, log it, and return a success status. No OMS request exists.
  • The scripts block in connect.yaml. The postDeploy and preUndeploy files exist in each application, but they are not declared, so a deployment creates no Subscription.
  • Authentication on the inbound order-updates and inventory-import endpoints. Both accept unauthenticated requests that write to your Project.
  • Order status, Line Item state, cancellation, and return handling. The inbound application applies only Add Delivery and Change ShipmentState.
  • Idempotency on both flows. The export has no external side effect in the template, while a repeated inbound Order webhook adds a second Delivery.
  • Least-privilege permissions. The template expects a pre-created API Client rather than declaring inheritAs.apiClient.scopes.
  • Meaningful tests. The suite asserts response codes for malformed requests only.

Whichever option you choose, the sync design in the next section is the same. Only the question of who implements it changes.

Design the sync flows

An OMS integration is a directional data sync between two systems that each own part of the Order lifecycle. This guide uses the standard Connect application types: an event application for the export, a service application for inbound updates, and an optional job application for reconciliation.

Export placed Orders

The export reacts to an Order and pushes it to the OMS. Use an event application, which receives Messages through a Subscription and a Connect-provisioned message broker.

Subscribe to every Message that represents an exported Order

Direct checkout, Recurring Order, and import flows do not necessarily emit the same Message. Select the required types from Cart and Order Messages. An incomplete selection can leave some Orders unexported without producing an error. Add Order lifecycle Messages only when the OMS must also receive changes made in commercetools. Subscribe to the smallest set that meets your requirements, and acknowledge anything else without acting on it.

Retrieve the Order instead of reading the Message payload

Retrieve the Order by resource.id. Subscriptions deliver at least once with no ordering guarantee, so a payload can describe an older state than the Order currently has. A payload that exceeds the queue size limit is omitted entirely and the notification arrives with payloadNotIncluded, which makes your largest Orders the ones that fail. Retrieving the Order removes both problems.

Make the export idempotent without local state

The same Message can arrive more than once. Send the commercetools orderNumber as the OMS external reference and let the OMS upsert on it, or query the OMS for an existing record before creating one. Connect applications are stateless and autoscaled, so an in-process set of processed identifiers is lost on restart and is not shared between instances. The orderNumber field is optional on an Order and unique across a Project, so confirm that your checkout sets it before you use it as the correlation key.

Store the OMS identifier on the Order

An Order has no top-level externalId field. Use SyncInfo, which exists to record synchronization activity such as an export, and write it with the Update SyncInfo update action. The action requires a Channel whose roles include OrderExport or OrderImport. Without that role the action fails with an InvalidInput error after the OMS has already created the Order, so create the Channel before the first export runs. Read the value back with the syncInfo(externalId="...") Query Predicate. A Custom Field is a valid alternative when you need to store more than an identifier and a Channel.

Acknowledge deliberately

Event applications and API Extensions use different response contracts. Follow Event application behavior and API Extension responses, and do not reuse acknowledgment logic between the two application types.
The message queue treats 102, 200, 201, 202, and 204 as an acknowledgment and retries every other response. Unacknowledged messages are retained for seven days, and push backoff applies when an application returns too many negative acknowledgments, so a sustained OMS outage slows delivery for every Message on the queue. Subscription delivery is retried for up to 48 hours on a TemporaryError, and for a shorter window on a ConfigurationError. Size your reconciliation schedule against those windows rather than against the queue alone.

Map each outcome to a status code on purpose:

OutcomeResponseReason
Exported successfully200, 202, or 204Nothing to retry
Message type you do not handle200Redelivery cannot help
Malformed envelope that can never be decoded200, with a log entry and an alertRetrying cannot make the Message valid
Transient OMS or network failureA status outside the acknowledgment set, or noneRedelivery is the recovery path
Order that permanently cannot be exported200, with a record for replayAn endless retry loop is avoided
Returning 200 for every error is the opposite failure: a transient OMS outage is acknowledged, the Message is discarded, and the Order silently never reaches the OMS.

Do not export your own writes back to the OMS

The inbound flow applies update actions that produce their own Messages: Change OrderState produces Order State Changed, and Change ShipmentState produces Order Shipment State Changed. If your export Subscription covers those types so that the OMS receives changes made in commercetools, the inbound flow re-triggers the export and export volume climbs continuously with no business cause. Filter changes made by your own API Client, or exit early when the Order already matches the state the OMS reported.

Apply inbound updates

Inbound updates arrive from the OMS. Use a service application as an authenticated webhook. In this mode, no API Extension is registered, the default two-second API Extension response limit does not apply, and the five-minute Connect service timeout applies instead. You authenticate the caller and write to commercetools yourself.

Do not implement inbound updates as an API Extension. An API Extension runs synchronously inside a commercetools API request, so OMS latency or an outage would delay or block Cart and Order operations.

Authenticate every request and validate the payload

The endpoint is reachable from the internet and writes to your Project. Verify a shared secret or a fully validated token, including signature, issuer, audience, and expiry, on every processing route. Leave only a liveness route unauthenticated. Keep the webhook secret in secured configuration.

Correlate by the stored identifier

Find the Order with the syncInfo(externalId="...") predicate or the equivalent Custom Field predicate. The API does not enforce uniqueness for SyncInfo.externalId, so reject zero or multiple matches and enforce uniqueness in the integration. Never infer the Order from position, sequence, or timing.

Read the Order before writing to it

Every update action requires the current version, and some require existing state. Add Delivery fails unless the Order already has shippingInfo for a single shipping mode, or shipping for multiple shipping modes. In Multiple Shipping Mode, the action also requires shippingKey. A shipment update on an otherwise valid Order fails when the required shipping data is missing.

Guard the transition instead of applying it unconditionally

A redelivered "shipped" notification must be a no-op, and a notification that arrives late must not overwrite a newer state. Compare the sequence or version the OMS supplies against the current state of the Order, and skip the write when the state is already correct or has moved past it. Handle a 409 version conflict by re-reading the Order and re-evaluating the decision. Re-sending the same actions after a conflict is how a single shipment becomes two Deliveries with duplicate tracking numbers.

The following handler applies a shipment update using that sequence: correlate, re-read, decide, write, and re-evaluate on conflict. Key the Delivery on the OMS shipment identifier so a redelivery finds the existing record instead of adding a second one.

Apply an OMS shipment update idempotentlytypescript
async function applyShipmentUpdate(
  apiRoot,
  omsOrderId: string,
  omsShipmentId: string,
  trackingId: string
) {
  const MAX_ATTEMPTS = 3;

  for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
    // Correlate on the identifier stored at export time
    const matches = await apiRoot
      .orders()
      .get({
        queryArgs: {
          where: `syncInfo(externalId="${omsOrderId}")`,
          limit: 2,
        },
      })
      .execute();

    // SyncInfo.externalId is not unique by the API, so enforce it here
    if (matches.body.results.length !== 1) {
      throw new Error(
        `Expected exactly one Order for OMS identifier ${omsOrderId}`
      );
    }

    const order = matches.body.results[0];

    // A redelivered notification is a no-op
    const alreadyApplied = order.shippingInfo?.deliveries?.some(
      (delivery) => delivery.key === omsShipmentId
    );
    if (alreadyApplied) {
      return order;
    }

    try {
      const updated = await apiRoot
        .orders()
        .withId({ ID: order.id })
        .post({
          body: {
            version: order.version,
            actions: [
              {
                action: "addDelivery",
                deliveryKey: omsShipmentId,
                parcels: [
                  { trackingData: { trackingId, isReturn: false } },
                ],
              },
              {
                action: "changeShipmentState",
                shipmentState: "Shipped",
              },
            ],
          },
        })
        .execute();

      return updated.body;
    } catch (error) {
      // Re-read and re-evaluate; never replay these actions against a new version
      if (error.statusCode === 409) continue;
      throw error;
    }
  }

  throw new Error(`Version conflict persisted for OMS identifier ${omsOrderId}`);
}
In Multiple ShippingMode, read the Deliveries from shipping[].shippingInfo.deliveries and pass the matching shippingKey in the Add Delivery action.

Return a status the OMS can act on

Use a success status when the update is applied or intentionally skipped, a client error for a payload that will never be valid, and a server error for a transient failure so the OMS retries. Neither the export nor the inbound flow sits on the checkout path, so a transient OMS or commercetools failure should reject the update and retry rather than drop it.

Reconcile drift

A scheduled job application repairs what the event and webhook paths miss: a dropped webhook, a Message that exhausted its retries, an Order that failed to export, and Inventory that has diverged. Add one whenever your business tolerance for drift is lower than the guarantees of at-least-once delivery.
Follow the documented Job application behavior and resource recommendations. The Connect documentation does not guarantee that scheduled runs cannot overlap, so take a durable lock with a time to live longer than the maximum run time. A crashed run then eventually releases the lock. Checkpoint your cursor after each page so the next run resumes instead of restarting, and stop with a margin before the timeout. A job should orchestrate large batch work rather than perform it in the container.

Every unit of work must be idempotent, because reconciliation deliberately reprocesses records that the event path may have already handled. Share one handler between the event path and the reconciliation path rather than writing a second implementation that can drift from the first.

Map OMS statuses to commercetools state

The mapping between the two status vocabularies is the most error-prone part of the integration, because commercetools separates overall Order, shipment, payment, custom workflow, and per-Line Item state. See the Order representations and Order update actions for the canonical fields and actions.
The built-in Order and shipment vocabularies differ, including the spelling of cancellation: OrderState uses Cancelled, while ShipmentState uses Canceled. Use the type definitions as the canonical value lists.

Use the following table as a starting point for an explicit OMS mapping:

OMS statuscommercetools targetUpdate actions
ReceivedCustom Order State ReceivedTransition State
Allocated or pickingLine Item StateTransition LineItem State
Shipped, with trackingshipmentState Shipped, plus a Delivery and ParcelChange ShipmentState, Add Delivery, Add Parcel to Delivery, Set Parcel Tracking Data
Partially shippedshipmentState Partial, plus one Delivery per shipmentChange ShipmentState, Add Delivery
DeliveredorderState CompleteChange OrderState
CancelledorderState CancelledChange OrderState
Return initiated or receivedReturn Item with Advised or Returned stateAdd ReturnInfo
Returned item assessedReturn shipment state BackInStock or UnusableSet ReturnShipmentState
When your required statuses do not exist as built-in orderState values, model them as a custom State machine and register the States and their transitions idempotently during deployment.
Split and partial fulfillment need particular care. The API does not validate cumulative Line Item quantities across Deliveries, as described in Multiple deliveries. A duplicate or miscounted inbound update therefore produces an Order that reports more items delivered than were bought, without any error. Your handler owns that check.
Returns are also two decisions, not one. ReturnShipmentState tracks the physical return, and ReturnPaymentState tracks whether the money was refunded. Set the payment state from an authoritative payment event rather than inferring a refund from the arrival of the goods.

Synchronize Inventory

Inventory synchronization is a separate flow with its own direction, cadence, and failure policy. Handle it as its own integration rather than as a side effect of Order updates, so you can tune it independently.

Decide first whether commercetools also writes Inventory. The InventoryMode of a Cart or Line Item controls this: TrackOnly and ReserveOnOrder deduct stock when the Order is created, and ReserveOnCart reserves stock as soon as a Line Item enters the Cart. Only None leaves Inventory untouched. When the OMS owns Inventory and also decrements it on the same Order, any mode other than None deducts the same units twice and produces drift that reconciliation reports forever. Either set the mode to None, or subtract the platform-side deduction in your mapping. See Inventory modes for the full behavior of each mode.
For OMS upserts, define a consistent SKU and supply location key convention. See Manage Inventory with InventoryEntry and Supply Channels versus Distribution Channels for the canonical Inventory model. The initial bulk Inventory load and its mapping onto the catalog belong to Integrate product data; this section covers only the steady-state updates the OMS owns.
When the OMS owns Inventory, apply its updates with Change Quantity for an absolute level, or Add Quantity and Remove Quantity for a delta. Absolute levels are safer under at-least-once delivery, because a repeated absolute update is a no-op while a repeated delta is not.
Inventory thresholds can emit Messages that trigger an asynchronous availability check against the system of record. They do not perform a blocking OMS check. For the threshold pattern that reduces per-Order OMS availability calls, see Plan integrations.

Two behaviors shape reconciliation:

  • Account for Inventory consistency. Order-driven and reservation-driven changes are eventually consistent, while direct Inventory API updates are immediately visible. Trail reconciliation behind the documented consistency window so temporary lag is not reported as drift. See Inventory checks and consistency.
  • Decide which system restocks canceled Inventory. Changing orderState to Cancelled records the business outcome for the Order, and commercetools documents no automatic restock for it. Require the Inventory owner to send an explicit restock update.

Run a periodic full snapshot in addition to the incremental updates. Incremental Inventory updates can be missed, and the drift is invisible until stock is oversold.

Configure and deploy the Connector

Configure the applications, permissions, and Subscription as one contract.

Grant only the permissions the enabled flows use

Declare them through inheritAs.apiClient.scopes so Connect generates a scoped API Client at installation, instead of asking an installer to supply credentials. The API Client that creates the Deployment requires manage_api_clients. The generated API Client needs permissions for the enabled Order, Inventory, Message, and registration flows. Inventory writes use manage_products. Message reconciliation requires view_messages, must be enabled for the Project, and can only reach back as far as the Project's Message retention window, which defaults to 15 days. If postDeploy creates resources, add manage_subscriptions, manage_channels, manage_types, and manage_states as applicable. See Modify a Connector and the canonical API scopes.

Separate configuration from secrets

Classify OMS settings according to the canonical connect.yaml configuration rules. Never place OMS credentials or webhook secrets in code or logs.

Build the Subscription destination from the injected variables

Connect deploys to both Google Cloud and AWS Regions, and the message broker follows the Region. Build the destination from the Event variables documented in Automation scripts, and support both brokers. Verify Subscription creation separately because Deployment status alone does not establish that automation-created resources exist.

Register resources idempotently

Create the Subscription, any custom States, and any Custom Types in postDeploy, and remove them in preUndeploy. Declare both in the scripts block of connect.yaml; a script file that is not declared never runs. Prefer creating the Subscription when absent and updating it in place, rather than deleting and recreating it, because the gap between the two operations drops the Messages emitted during it.

Verify the registration rather than inferring it from the Deployment status

Query Subscriptions for the expected key after every deployment, and check Deployment logs. This verification confirms whether the automation script created the expected resource.

Validate the OMS connection at deploy time

Have postDeploy make a test call to the OMS so bad credentials surface immediately instead of on the first Order. Decide whether that failure fails the deployment or only warns, and record the decision.

Verify the round trip

Add automated tests before you deploy. Mock both the OMS API and the commercetools API, and assert which actions the code takes:

  • Each supported Message type routes to the intended handler, and unhandled types are acknowledged without an OMS call.
  • The export retrieves the Order by identifier and handles an omitted payload.
  • A redelivered export Message produces one OMS record, not two.
  • Each status code in the acknowledgment table is returned for the outcome it represents.
  • The self-change filter prevents an inbound status write from re-triggering the export.
  • The inbound endpoint rejects unauthenticated and malformed requests.
  • A redelivered inbound update is a no-op, and a stale update does not overwrite a newer state.
  • A version conflict causes a re-read and re-evaluation, not a replayed set of actions.
  • Cancellation and return paths apply the intended actions and leave payment state alone.
  • Reconciliation is safe to re-run and stops cleanly at its checkpoint.
  • postDeploy creates one Subscription, a repeated deployment does not duplicate it, and preUndeploy removes it.

After deployment, trace a real Order end to end:

  1. Confirm that one Subscription exists with the expected key, destination, and Message types.
  2. Place an Order and confirm that it appears in the OMS with the expected mapping.
  3. Confirm that the Order in commercetools carries the OMS identifier in its SyncInfo.
  4. Drive a status change, a shipment with tracking, and a delivery in the OMS, and confirm each one on the Order.
  5. Exercise a cancellation and a return, and confirm the resulting state and Inventory effect.
  6. Redeliver the same export Message and repeat the same inbound update, and confirm that neither produces a duplicate.
  7. Make the OMS fail temporarily, and confirm that the work is retried rather than lost.
  8. Run reconciliation against a deliberately missed update and confirm that it repairs the drift.
Some expected behavior looks like failure during testing. A default sandbox deployment scales to zero and takes approximately 15 seconds to start again, which exceeds the 10-second acknowledgment deadline, so early events are redelivered until the application is warm. Subscription delivery has no guaranteed time frame and can be delayed by several minutes. Order-driven and reservation-driven Inventory changes can lag by up to 10 seconds. Confirm the deployment environment and the elapsed time before treating any of these as a defect.
In production, monitor Subscription health, acknowledgment failures, processing duration for each flow, version conflict rates, reconciliation lag, and the count of Orders with missing SyncInfo. Log a correlation key on every line: use resource.id with sequenceNumber for Messages, and your own key for inbound requests. Log identifiers and decisions rather than payload bodies, so Customer data does not reach the logs. Define how an operator replays a failed Order after a fix, and record it alongside the Connector.

Troubleshoot observable symptoms

Match the symptom you observe to its likely cause and resolution:

SymptomLikely causesChecks and resolution
No events reach the exportThe Subscription is missing. The scripts block was never declared in connect.yaml. Or postDeploy built a destination for the wrong broker and Subscription creation failed. Or delivery stopped after a configuration error.Query Subscriptions by key and inspect the health status. Compare the destination with CONNECT_SUBSCRIPTION_DESTINATION. Review deployment logs.
Most Orders export, but subscription or migrated Orders never doThe Subscription covers Order Created only.Add Order Created From Recurring Order and Order Imported to the Subscription and the handler.
The same Order retries for hours and then disappearsThe handler returns a status outside the acknowledgment set for a Message that can never succeed.Acknowledge permanently unprocessable Messages, record them for replay, and alert instead of looping.
Logs show success, but the OMS has no recordThe handler acknowledged before the OMS call, or an error was swallowed and a success status returned.Check OMS-side activity, not only Connector logs. Distinguish transient failures from terminal ones and let transient failures redeliver.
The largest Orders fail while smaller ones succeedThe Message exceeded the queue size limit and arrived with payloadNotIncluded.Retrieve the Order by resource.id instead of reading the payload.
Export volume climbs with no matching Order volumeThe export subscribes to lifecycle Messages that the inbound flow produces.Filter changes made by your own API Client, or exit early when the Order already matches the reported state.
The OMS created the Order, but the correlation write failedThe Channel used in Update SyncInfo lacks the OrderExport or OrderImport role.Add the role to the Channel, or create a dedicated export Channel, then replay the affected Orders.
Inbound updates return a version conflict on every attemptConcurrent writes to the Order, or a retry that replays the same actions against a refreshed version.Re-read the Order and re-evaluate the decision on each attempt instead of resending the original actions.
One shipment appears as two DeliveriesThe inbound handler is not idempotent, or a conflict retry re-applied Add Delivery.Check current Deliveries before adding one, and key the check on the OMS shipment identifier.
Delivered quantities exceed the quantities orderedDuplicate or miscounted Deliveries. The API does not validate cumulative quantities.Validate the running total in the handler before adding a Delivery.
An Order regresses to an earlier statusA late notification overwrote a newer state.Guard the transition on the OMS sequence or the current Order state.
A cancellation update is rejectedCancelled was sent to shipmentState, or Canceled to orderState.Use Cancelled for OrderState and Canceled for ShipmentState.
A shipment update fails on a valid OrderThe Order has no shippingInfo or shipping, which Add Delivery requires.Confirm the shipping data exists before applying the Delivery, and fix the checkout flow that omitted it.
Stock stays depleted after a cancellationNo system restocked the canceled quantity.Confirm the restock behavior in your Project, and have the OMS send an explicit Inventory update when it owns the restock.
Reconciliation reports drift that disappears on the next runThe comparison ran inside the 10-second Inventory consistency window.Trail the comparison window behind the current time.
Reconciliation double-processes recordsTwo scheduled runs overlapped.Take a durable lock with a time to live longer than the 30-minute job timeout.
Events are redelivered only in testingA sandbox deployment scaled to zero and took approximately 15 seconds to start.Test against a warm deployment, or account for the cold start in the acknowledgment budget.
Deployment succeeds but requests fail at runtimeThe API Client scopes do not cover the enabled flows.Compare the flows against the scope table and keep the final set least-privileged.
The Connector cannot be deployed at allThe chosen integration is vendor-hosted rather than an installable Connector.Follow the vendor's setup instructions; there is nothing to deploy in Connect.