ml-connector
Sage X3ShipStation

Sage X3 and ShipStation integration

Sage X3 manages your manufacturing and distribution operations, inventory, and order fulfillment. ShipStation connects your orders across all your sales channels and orchestrates shipping. Linking the two keeps your order pipeline and shipment tracking in sync without manual re-entry. New orders from ShipStation post into Sage X3 as sales documents, and shipment confirmations from ShipStation update order status and trigger inventory adjustments in X3. ml-connector handles the different authentication paths and the timing gaps between the two systems.

How Sage X3 works

Sage X3 exposes customers, products, sales orders, and inventory through REST or GraphQL APIs, with GraphQL (Xtrem) recommended for new integrations on X3 V12 and later. Authentication uses OAuth2 client credentials delivered as a JWT bearer token via Connected Application, or HTTP Basic Authentication on the legacy REST api1 path. Access tokens expire in five minutes and refresh tokens are valid for thirty days. Sage X3 does not support outbound webhooks or event notifications, so orders and shipments are detected by polling the modifiedDateTime or updatedDate fields on records. The server URL, port, and X3 folder name are customer-specific with no central tenant registry; each customer must provide their own X3 instance details.

How ShipStation works

ShipStation exposes orders, shipments, customers, and inventory through REST APIs available in both V1 and V2 versions, with V2 recommended for new integrations. Authentication uses API key headers in V2 (API-Key header without Bearer prefix) or HTTP Basic Auth with base64-encoded key and secret in V1. ShipStation supports outbound webhooks for order creation and shipment events, though webhook payloads contain only a pointer to the resource and require an authenticated follow-up GET to fetch the full data. Rate limits are 200 requests per minute in V2 and 40 per minute in V1, with headers provided to track remaining quota. All V1 timestamps are in PST/PDT timezone, not UTC. ShipStation's order status becomes immutable once an order is marked shipped or cancelled.

What moves between them

The main flow runs from ShipStation into Sage X3. New orders created in ShipStation are pulled via polling (since ShipStation ORDER_NOTIFY fires only on creation, not edits) and posted into X3 as sales orders mapped to matching customers and products. Shipment confirmations from ShipStation flow back to X3 via webhook (SHIP_NOTIFY and FULFILLMENT_SHIPPED events) to update order fulfillment status and trigger inventory adjustments. Product and customer reference data is synced bidirectionally to ensure order lines land on valid X3 products and that new customers created in ShipStation are registered in X3.

How ml-connector handles it

ml-connector caches the Sage X3 OAuth2 bearer token and refreshes it before the five-minute expiry window closes, eliminating failed API calls due to stale credentials. For ShipStation webhooks, ml-connector receives the ORDER_NOTIFY and SHIP_NOTIFY event pointers and immediately fetches the full order or shipment data with an authenticated V2 API call to avoid losing information in the tight time window before webhook delivery is retried. On the Sage X3 side, ml-connector polls for new and modified sales orders by querying the modifiedDateTime field, since X3 has no push notifications. Customer and product masters are synced first, so every sales order line references an X3 product and customer that already exists, preventing order import failures. ShipStation's rate limits are tracked via response headers, and ml-connector backs off and retries when approaching the quota. All datetimes from ShipStation V1 are converted from PST/PDT to UTC on ingest to prevent downstream time skew. Every order and shipment carries a full audit trail and can be replayed if a mapping or downstream call fails.

A real-world example

A mid-market e-commerce distributor runs Sage X3 on-premise to manage supplier relationships, procurement, and order fulfillment. Their sales flow through multiple channels aggregated into ShipStation, which generates labels and tracks carrier shipments. Before the integration, the fulfillment team exported orders from ShipStation daily and manually keyed each one into X3, creating delays and errors as channel orders piled up faster than data entry could handle. With ShipStation and Sage X3 connected, each new order flows automatically from ShipStation into X3 as a sales document, and shipment confirmations flow back to close out the order and trigger inventory moves. Order backlog in X3 stays current with shipment activity, and the manual export-and-rekey step is eliminated.

What you can do

  • Pull new orders from ShipStation and post them into Sage X3 as sales orders, mapped to the correct customers and products.
  • Receive ShipStation shipment notifications and update order fulfillment status in Sage X3, triggering inventory moves.
  • Sync customer and product masters bidirectionally to ensure order lines reference valid X3 entities.
  • Refresh Sage X3 OAuth2 tokens before expiry and handle ShipStation webhook payloads by fetching full resource data on receipt.
  • Track ShipStation rate limits via response headers and retry failed orders with a full audit trail for replay on downstream failures.

Questions

Which direction does data move between Sage X3 and ShipStation?
The main flow is ShipStation into Sage X3. Customer orders created or modified in ShipStation are pulled and posted into X3 as sales orders. Shipment confirmations from ShipStation webhook events flow back into X3 to update order status and trigger inventory adjustments. Customer and product masters are synced in both directions to keep reference data aligned.
Why does ml-connector need to fetch full data from ShipStation webhook payloads?
ShipStation webhooks deliver only a pointer (resource_url and resource_type) rather than the full order or shipment object. ml-connector immediately fetches the complete data using an authenticated API call to avoid losing information if the webhook is retried or the order is modified before the full data is retrieved. This is critical because the order may become immutable (shipped or cancelled) before a retry, locking out changes.
How does the integration handle Sage X3's five-minute token expiry and ShipStation's rate limits?
ml-connector caches the Sage X3 OAuth2 bearer token and refreshes it proactively before the five-minute window closes, eliminating failed calls due to stale credentials. For ShipStation, ml-connector monitors the rate limit headers (X-Rate-Limit-Remaining, X-Rate-Limit-Reset) in every response and backs off when approaching the quota, then retries with exponential jitter to stay within the 40-200 requests per minute limits depending on API version.

Related integrations

Connect Sage X3 and ShipStation

Free to use. Add your credentials, ping your real systems, and see if we fit.

Get started