ml-connector
Sage X3Coupa

Sage X3 and Coupa integration

Sage X3 runs manufacturing finance and procurement. Coupa runs enterprise procurement and spend management. Connecting the two keeps your supplier master and purchase orders synchronized, and brings Coupa invoices and payments back into X3 for reconciliation and close. New suppliers in X3 appear in Coupa, purchase orders sync downstream, and invoice postings route into X3's GL accounts without manual entry. ml-connector bridges the OAuth2 and HTTP Basic authentication on each side and handles X3's token refresh cycle and Coupa's rate limits.

How Sage X3 works

Sage X3 exposes suppliers, purchase orders, supplier invoices, GL accounts, and cost centers through REST and GraphQL APIs. The REST endpoint (api1) uses HTTP Basic authentication and requires explicit enablement by the customer admin; the GraphQL endpoint (Xtrem) uses OAuth2 client credentials via a Connected Application. Access tokens expire in 5 minutes and must be refreshed using a 30-day refresh token. X3 has no native webhooks, so connectors must poll using updatedDate or modifiedDateTime fields on each entity class to detect changes since the last sync. The REST api1 endpoint has a default page size of 20 records and no published rate limits; on-premise deployments are constrained by server capacity, while cloud limits are undocumented. Server URL, port, and application folder are customer-specific with no central tenant registry.

How Coupa works

Coupa exposes suppliers, purchase orders, invoices, payments, and reference tables through a REST API with OAuth2 client credentials authentication. Coupa also supports webhooks for six event types: requisition-events, purchase-order-events, invoice-events, supplier-events, expense-report-events, and payment-events. Webhook signatures are verified using HMAC-SHA256. Coupa imposes a 30-second default request timeout on all calls, rate limits responses on 5xx and 429 status codes, and caps webhook body size at 256KB. The instance URL is customer-specific and follows the pattern {instanceUrl}/api (e.g., https://acme.coupahost.com/api). Coupa recommends up to 3 retry attempts with exponential backoff capped at 30 seconds on rate-limited calls.

What moves between them

The main flow runs from Sage X3 into Coupa. Supplier master data and purchase orders are polled from X3 on a schedule (typically daily for master data, per procurement workflow for orders), then posted into Coupa via the REST API. Coupa invoice and payment events are delivered to ml-connector via webhook or polled through the REST API, then mapped to X3's accounts payable invoices and GL account entries. Supplier changes flow both directions so X3 and Coupa remain aligned. GL postings in Coupa are read-only, so ml-connector never writes financial entries back to Coupa; instead, it reads Coupa invoices and forwards them to X3's GL journal entry API.

How ml-connector handles it

ml-connector stores X3 credentials and refreshes the OAuth2 bearer token when it expires (every 5 minutes), or falls back to HTTP Basic authentication if the customer has enabled the legacy REST api1 endpoint. For Coupa, it presents OAuth2 credentials on each call and retries on 429 rate-limit responses with exponential backoff capped at 30 seconds, respecting the 30-second request timeout. Supplier records are matched by external ID or name to prevent duplicates in Coupa. Purchase orders are fetched from X3 using updatedDate or modifiedDateTime polling and posted to Coupa's REST endpoint, then tagged with the X3 purchase order number for traceability. Incoming Coupa invoice events are parsed from webhook payloads and matched to X3 purchase orders and suppliers by external reference, then formatted as GL journal entries or accounts payable invoices in X3. Cost center allocation is preserved from the original X3 purchase order so invoices post to the correct GL dimensions. Every record carries a full audit trail and can be replayed if a downstream call fails.

A real-world example

A mid-market distribution company runs Sage X3 for finance, inventory, and procurement, and uses Coupa for spend visibility and vendor compliance across 150 suppliers and 2000 purchase orders annually. Before the integration, the procurement team entered new suppliers and purchase orders into X3, then re-entered them into Coupa for compliance tracking and payment approval workflows, creating duplicate data entry and version-control headaches. When invoices came back from Coupa approved, the AP team downloaded them and keyed them into X3 for GL posting. With Sage X3 and Coupa connected, new suppliers and purchase orders flow from X3 to Coupa automatically, Coupa's approval workflows execute without X3 re-keying, and invoices post back into X3's GL accounts with cost centers intact. The AP team runs month-end close faster, and the two systems no longer diverge.

What you can do

  • Sync Sage X3 suppliers and purchase orders to Coupa on a schedule, with delta detection to avoid re-sending unchanged records.
  • Bring Coupa invoice and payment events back into Sage X3's accounts payable and general ledger, mapped to the original purchase order and cost center.
  • Match suppliers between X3 and Coupa by external ID or name to prevent duplicates and maintain a clean vendor master in both systems.
  • Handle X3 token expiry and refresh cycles, plus Coupa rate limits and 30-second timeouts, with automatic retries and backoff.
  • Preserve GL cost center allocation from the original X3 purchase order so invoices land on the correct account and dimension.

Questions

Does every change in Sage X3 appear immediately in Coupa?
No. Because Sage X3 does not support native webhooks, ml-connector polls X3's updatedDate and modifiedDateTime fields on a schedule (typically daily for suppliers, per your procurement workflow for purchase orders). Coupa receives the new or updated records within one polling cycle and can trigger its own approval or enrichment workflows. This design avoids continuous polling overhead while keeping data fresh.
How does the integration handle Sage X3 token expiry and Coupa rate limits?
Sage X3 access tokens expire every 5 minutes; ml-connector refreshes the token using the 30-day refresh token before each call. Coupa enforces a 30-second request timeout and rate limits on 5xx and 429 responses; ml-connector retries up to 3 times with exponential backoff capped at 30 seconds. Both systems are handled transparently so rate limits or token expiry do not interrupt your sync.
Can invoices be pushed back into Sage X3 from Coupa?
Yes. Coupa invoice events are captured via webhook or polled through the REST API, then formatted as accounts payable invoices or GL journal entries in X3, mapped to the original purchase order and supplier. GL postings in Coupa are read-only, so ml-connector does not write financial entries back to Coupa; the flow is one-way for accounting records. Supplier and purchase order data can flow both directions to keep master data synchronized.

Related integrations

Connect Sage X3 and Coupa

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

Get started