Sage Intacct integration, in production

Sage Intacct, bridged properly.

Intacct speaks two dialects, REST and XML. We speak both, batch aggressively, and treat every write as something that will be audited, because it will. Everything here runs in production for a $60M freight brokerage, multi-entity, with a Salesforce-native TMS feeding it.

Already have a Salesforce-to-Intacct bridge that skips records without telling anyone? We've taken one over.

215K → ~500
API calls per month → per day
$2.36M
Payment records backfilled, 0 dupes
200K
GL rows refreshed in about 2 min
24 of 24
Silent skips reproduced in the old bridge
Bridge takeover

The bridge the last vendor couldn't keep alive.

An outsourced TMS-to-ERP bridge was skipping records, burning API quota, and leaving payments unrecorded. We mirrored its behavior from the outside, without source access, and replaced it with something owned.

4 API CALLS PER RECORD → 1

Owned replacement

Fail-closed dedup, pre-flight validation, verify-after-write readback, a single-runner interlock, and an append-only run journal. The incumbent's silent-skip failure mode reproduced 24 of 24 times; about $18K a year in avoidable API tier alone.

903 RECORDS · $2.36M · 0 DUPES

Payment write-back watcher

Detects invoices the incumbent marked paid without creating the payment records the TMS roll-ups depend on, and creates them idempotently. A 1,052-invoice outage window backfilled with zero failures.

BEHAVIOR FIRST

Document before replacing

The incumbent's behavior is mapped from the outside before anything is replaced, so the new bridge matches what finance already relies on, minus the silent failures.

The full story, with the numbers: read the case study →

Other side of the bridge: live mirrors, Flow webhooks, auth isolation, and audited write-back on the Salesforce org.

See the Salesforce page →
What we build on Intacct

Reporting your controller can sign off on.

Intacct is a strong ledger. We make its data easy to ask questions of, without hammering the API.

215K CALLS/MO → ~500/DAY

Dual-path Intacct client

One client for REST (OAuth2) and XML Web Services with automatic fallback for XML-only functions like AR aging. Replaced an abandoned integration with a batched design at a few hundred calls a day.

NIGHTLY · MULTI-ENTITY

AR / AP / aging cache

AR invoices, AP bills, and aging buckets pulled into a queryable cache with point-in-time snapshots, across entities.

200K GL ROWS · ~2 MIN

GL financial dashboards

Nightly full-replace pull of income-statement lines with correct debit and credit normalization: P&L, trailing-12 margin, expense breakdown, per-entity comparison. Full replace because the GL is retroactively editable.

UNDOCUMENTED FILTERS, FOUND

Budget vs. actual

Budget line items per fiscal-year header bucketed against actuals by account prefix, after discovering the filter and field names the docs don't mention.

180-DAY WINDOW · IDEMPOTENT

Duplicate-payment scanner

Clusters live AR and AP on normalized document keys, flags any set with an already-paid member as double-payment risk, emails CSV evidence, and never re-alerts on a reviewed set.

HMAC-SIGNED · SINGLE-PURPOSE

One-click actions for non-users

Finance staff without dashboard logins resolve a duplicate straight from the email through expiring signed tokens. GET renders, POST mutates, so mail-scanner link prefetch can't trigger anything.

Anatomy of a safe write

Every write to your ledger earns its place.

1

Pre-flight

Validate the record against what Intacct will accept, before the API sees it.

2

Fail-closed dedup

If we can't prove it isn't a duplicate, it doesn't post.

3

Single runner

An interlock so two processes can never write the same batch.

4

Verify after write

Read the record back and compare. A write isn't done until it checks out.

5

Run journal

Append-only history of every run, so any number can be traced to the call that made it.

Watchdogs

Silence is a failure mode. We alert on it.

CREDENTIALS

Credential-health probes

An expiring or revoked credential pages someone before the nightly job discovers it.

LIVENESS

Heartbeat liveness

Alerts on unexpected service-account activity as well as on missing activity.

FRESHNESS

Stale-cache auto-refresh

Dashboards never quietly serve yesterday's ledger as today's.

DIGEST

Activity digest

A daily summary that costs zero extra API calls.

Cadence: checks run on 12-hour, 4-hour, 6-hour, and daily schedules, so no problem waits long to be seen.

FAQ

Sage Intacct integration questions

Do you use the Sage Intacct REST API or the XML API?

Both. One client speaks REST (OAuth2) and XML Web Services, with automatic fallback to XML for functions that are XML-only, such as AR aging.

Can you connect Salesforce or a Salesforce-based TMS to Sage Intacct?

Yes. We have taken over a failing outsourced TMS-to-ERP bridge with an owned replacement that uses fail-closed dedup, pre-flight validation, and verify-after-write readback. See the Salesforce side →

Does your integration work across multiple Intacct entities?

Yes. AR, AP, and aging data are pulled across entities into a queryable cache with point-in-time snapshots, and the GL dashboards include per-entity comparison.

How do you keep API usage under control?

By batching. We replaced an abandoned integration that was burning about 215,000 calls a month with a batched design at a few hundred a day.

Can you find duplicate or double payments in Intacct?

Yes. The scanner clusters live AR and AP on normalized document keys over a 180-day window, flags any set with an already-paid member as double-payment risk, emails CSV evidence, and never re-alerts on a reviewed set.

Will your integration change my Sage Intacct data?

Reporting and monitoring paths are read-only. Where a write path exists, such as payment records, it is idempotent, fail-closed, verified by readback after every write, and recorded in an append-only run journal.

Tell us where your Intacct data needs to go.

No pitch decks, no rip-and-replace. Your ledger stays exactly as it is. You'll hear back from a human, usually the founder.