ml-connector
Sage X3Plaid

Sage X3 and Plaid integration

Sage X3 manages your complete financial and operations record. Plaid connects your bank accounts and provides transaction feeds. Connecting them ends manual bank reconciliation by flowing verified bank transactions directly into your Sage X3 general ledger as journal entries. Transaction data arrives from Plaid on a webhook, ml-connector verifies each one with signature validation, maps it to the correct GL account and cost center, and posts it into Sage X3 with a full audit trail so reconciliation starts already complete.

How Sage X3 works

Sage X3 is deployed on-premise or in a Sage-managed cloud environment and exposes GL accounts, journal entries, suppliers, customers, and inventory through REST (api1 at http(s)://<server>:<port>/api1/<application>/<folder>/<CLASS>) or GraphQL (Xtrem at http(s)://<server>:<port>/xtrem/api). Authentication uses OAuth2 client credentials with JWT bearer tokens for GraphQL, or HTTP Basic Auth for the REST api1 legacy path. Access tokens expire in 5 minutes and refresh tokens last 30 days. Each customer runs on a customer-specific server URL and port; there is no central tenant registry. Sage X3 does not support outbound webhooks, so changes are detected by polling the updatedDate or modifiedDateTime fields on records.

How Plaid works

Plaid is a cloud financial data network connecting to users' bank and investment accounts via REST endpoints at https://production.plaid.com. It requires Plaid-managed authentication: client_id and secret supplied as PLAID-CLIENT-ID and PLAID-SECRET headers plus per-user access tokens obtained via the Plaid Link flow. Plaid delivers transaction and account data through webhooks (webhook_type TRANSACTIONS, ITEM, INVESTMENTS_TRANSACTIONS, LIABILITIES), posted as HTTP POST to a configured endpoint. Each webhook includes an ES256 JWT signature; ml-connector must verify the signature using Plaid's JWK public key, check that the alg is ES256, reject if the iat claim is more than 5 minutes old, and compare the SHA-256 of the raw body to the request_body_sha256 claim. Webhooks are retried for up to 24 hours with exponential backoff if not acknowledged within 10 seconds.

What moves between them

Bank transaction data flows from Plaid into Sage X3. When a transaction webhook arrives from Plaid, ml-connector verifies the ES256 signature, maps the Plaid account to a Sage X3 GL bank clearing account and cost center, and posts a journal entry into Sage X3 with debit and credit lines. Each transaction carries metadata (date, amount, counterparty, Plaid transaction ID) and is recorded in the audit trail so it can be replayed if a downstream Sage X3 write fails. The flow is unidirectional: Sage X3 does not write back to Plaid.

How ml-connector handles it

ml-connector receives Plaid webhooks at a registered HTTPS endpoint and immediately verifies every webhook using Plaid's ES256 JWT signature, rejecting any with an invalid signature, non-ES256 algorithm, or stale iat claim (older than 5 minutes). It stores Plaid credentials (client_id and secret) encrypted and presents them in the PLAID-CLIENT-ID and PLAID-SECRET headers on every API call. On the Sage X3 side, ml-connector either uses OAuth2 client credentials (for GraphQL, preferred on Sage X3 v12+) or HTTP Basic Auth (for REST api1 on v6+), storing credentials encrypted and refreshing the OAuth bearer token before it expires at the 5-minute mark. Bank account mappings link each Plaid account to a Sage X3 GL clearing account by account number, and transactions are posted with configurable GL account and cost center overrides per customer. Because Sage X3 REST api1 has no published rate limits and is constrained by on-premise server capacity or undocumented cloud limits, ml-connector spaces requests and backs off on error. Every transaction webhook is idempotent: ml-connector stores the Plaid transaction ID and skips re-posting if a matching entry already exists in the audit log.

A real-world example

A professional services firm uses Sage X3 for project accounting and cost tracking, and maintains checking and savings accounts at two banks connected via Plaid. Each month, the accountant manually downloaded bank statements, categorized transactions, and hand-entered them into Sage X3's GL, then spent hours reconciling the bank clearing accounts against the posting. With Sage X3 and Plaid connected, every bank transaction flows in via webhook as a journal entry posted to the correct project cost center and GL account. The accountant can now verify and close the bank accounts on day one of month-end close, freeing up two days of rework each cycle.

What you can do

  • Post verified bank transactions from Plaid into Sage X3 as GL journal entries with the correct accounts and cost centers.
  • Verify every Plaid webhook using ES256 JWT signature validation and the JWK public key, rejecting invalid or stale signatures.
  • Map Plaid bank accounts to Sage X3 GL clearing accounts and route each transaction to the appropriate GL account and cost center.
  • Authenticate Plaid with the required client_id and secret headers, and Sage X3 with OAuth2 or HTTP Basic Auth, storing all credentials encrypted.
  • Maintain a complete audit trail of every transaction, idempotent replay failed postings, and handle Sage X3 rate limits and token expiry.

Questions

How does ml-connector verify Plaid webhook signatures?
Every Plaid webhook includes an ES256 JWT signature. ml-connector retrieves Plaid's public JWK, verifies that the algorithm is ES256, checks that the iat claim is not more than 5 minutes old, and computes the SHA-256 of the raw webhook body and compares it to the request_body_sha256 claim in the JWT. Any mismatch or invalid signature is rejected.
Does the integration require Sage X3 on-premise or cloud, and which API should be used?
Sage X3 works both on-premise and in Sage-managed cloud. For v12 or later, use the GraphQL Xtrem API with OAuth2 client credentials, which is more modern. For v6 through v11, use the REST api1 legacy path with HTTP Basic Auth. ml-connector handles both; the choice depends on your Sage X3 version and whether Basic Auth is enabled in nodelocal.js by your admin.
What happens if a Plaid webhook fails to post into Sage X3?
ml-connector stores the transaction in the audit log with idempotent deduplication via the Plaid transaction ID. When retried, the same webhook will not create a duplicate entry. If a post fails, the transaction is logged with full context (date, amount, accounts, error reason) so it can be investigated and replayed once the issue is resolved.

Related integrations

Connect Sage X3 and Plaid

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

Get started