ml-connector
AcumaticaTableau

Acumatica and Tableau integration

Acumatica runs financials, distribution, and procurement. Tableau builds the dashboards finance and operations teams watch. Connecting the two means the bills, journal entries, GL balances, and order data that live in Acumatica reach the data layer Tableau reports on, and the extracts behind each dashboard refresh once new data lands instead of on a fixed nightly timer. Tableau holds no vendors, invoices, or GL accounts of its own, so the flow runs one way: Acumatica is the system of record and Tableau is the reporting surface. ml-connector handles the very different APIs on each side and moves the data on a schedule you control.

How Acumatica works

Acumatica Cloud ERP exposes vendors, AP bills, purchase orders, AP payments, GL accounts, journal transactions, customers, and sales invoices through its Contract-Based REST API. Each instance serves a version-locked URL of the form /entity/Default/{version}/{Entity}, where the endpoint version must match the running ERP release or the call returns 404. It authenticates with OAuth 2.0 through the built-in identity server or a legacy login session cookie, and every field value in a request or response is wrapped in a value object. Acumatica can push record changes via its Push Notifications system, but the reliable pattern is polling each entity on LastModifiedDateTime with $top and $skip offset paging.

How Tableau works

Tableau is a BI and visualization platform, not a finance system, so it has no native vendor, invoice, purchase order, or GL account objects. Its Tableau Server REST API exposes data sources, workbooks, views, projects, extract refresh tasks, and jobs under a versioned, site-scoped path. A connector authenticates with a Personal Access Token, exchanging the token for a session token sent as the X-Tableau-Auth header on every call, and must store the site LUID returned at sign-in because nearly every URL requires it. Data sources are published or updated and then refreshed via POST to the refresh endpoint, which returns an async job ID to poll. Tableau emits webhooks for events such as datasource-refresh-succeeded and datasource-refresh-failed.

What moves between them

The flow runs one way, from Acumatica into the Tableau reporting pipeline. On the cadence you set, ml-connector reads Acumatica bills, journal transactions, GL account balances, purchase orders, and AP payments and writes them into the database or extract that a Tableau data source is built on, then triggers an extract refresh so the workbooks rebuild on the new figures. Reference data such as GL accounts and cost centers is read from Acumatica so each dashboard measure maps to a real account. Tableau has no finance entities to write back, so ml-connector never pushes records into Tableau as ERP data; it only lands data for the data source and orchestrates the refresh.

How ml-connector handles it

ml-connector stores both credential sets encrypted. On the Acumatica side it requests an OAuth 2.0 bearer token from the instance identity server, or holds a login session and calls logout so it does not exhaust the concurrent-session license, and it pins the exact endpoint version per customer since a mismatch returns 404. It reads each finance entity by polling on LastModifiedDateTime with $top and $skip, storing the high-water mark after each run, because Acumatica push notifications retry only five times with no dead-letter queue and are not safe as the sole trigger. On the Tableau side it signs in with a Personal Access Token, captures the session token and site LUID, and re-authenticates on a 401 since the session expires after 240 minutes. After data lands, it calls the Tableau refresh endpoint and polls the returned job until it reports Success or Failed. Tableau webhooks carry no signature, so ml-connector verifies a secret token in the destination URL rather than an HMAC. Acumatica has no idempotency header, so reads are deduped on the natural key and a BullMQ jobId so a re-read record is not double-counted. Every record carries a full audit trail and can be replayed if a refresh or a downstream call fails.

A real-world example

A mid-sized distribution company runs Acumatica for purchasing, inventory, and finance, and its leadership team watches spend and margin in a set of Tableau dashboards. Before the integration, an analyst exported AP bills and GL balances from Acumatica to spreadsheets every few days, reshaped them by hand, and republished the Tableau extract, so the dashboards were always a few days stale and month-end reporting meant a scramble of manual pulls. With Acumatica and Tableau connected, new bills and journal entries land in the data source within the polling window and the extract refreshes on its own, so the dashboards track current AP and GL figures. The analyst stops exporting spreadsheets, and the leadership view reflects what Acumatica posted earlier the same day.

What you can do

  • Read Acumatica bills, journal transactions, GL balances, purchase orders, and AP payments into the data source behind your Tableau dashboards.
  • Trigger a Tableau extract refresh after new Acumatica data lands and poll the refresh job to confirm it succeeded.
  • Map Acumatica GL accounts and cost centers so each Tableau measure resolves to a real account.
  • Authenticate Acumatica with OAuth 2.0 or session login and Tableau with a Personal Access Token and site LUID.
  • Poll Acumatica on LastModifiedDateTime with jobId dedup, retries, and a full audit trail on every record.

Questions

Which direction does data move between Acumatica and Tableau?
Data moves one way, from Acumatica into the Tableau reporting pipeline. ml-connector reads bills, journals, GL balances, and order data from Acumatica, lands them where a Tableau data source reads them, and refreshes the extract. Tableau has no native vendor, invoice, or GL objects, so ml-connector never writes ERP records back into Tableau.
How does the integration keep Tableau dashboards current instead of waiting on a nightly schedule?
After it lands new Acumatica data, ml-connector calls the Tableau extract refresh endpoint and polls the async job it returns until the status is Success or Failed. It also subscribes to Tableau datasource-refresh-succeeded and datasource-refresh-failed webhooks, so a failed refresh surfaces as an alert rather than a silently stale dashboard. Refreshes fire when data actually changes, not only on a fixed timer.
Does Acumatica push changes, or does ml-connector poll for them?
Polling is the default. Acumatica can send push notifications, but its webhook destination retries only five times with no dead-letter queue, so it is not safe as the only trigger. ml-connector polls each Acumatica entity on LastModifiedDateTime with $top and $skip paging and stores a high-water mark, and it pins the exact endpoint version per customer because a version mismatch returns a 404.

Related integrations

Connect Acumatica and Tableau

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

Get started