ml-connector
Sage 50BILL

Sage 50 and BILL integration

Sage 50 is the accounting system of record, installed on a Windows machine. BILL handles the accounts payable workflow in the cloud, from bill approval to vendor payment. Connecting the two keeps your vendor list and open bills in agreement and posts payment status back where the books live. Vendors and approved bills move from Sage 50 into BILL, and once BILL pays a bill the payment is recorded against the matching Sage 50 purchase invoice. ml-connector handles the very different access models on each side and moves the data on a schedule you control.

How Sage 50 works

Sage 50 has no cloud REST API. Integration runs through a local Windows agent that uses the Sage 50 .NET SDK on the US edition or the Sage Data Objects COM library on the UK edition, reading and writing vendors, purchase invoices, AP payments, GL accounts, and customers. The agent authenticates with a dedicated Sage username and password against the company data files and must run in an interactive desktop session, not as a headless service. Sage 50 has no webhooks and no event stream, so changes are detected by polling modified records on a schedule against the last sync time.

How BILL works

BILL exposes vendors, bills, payments, invoices, customers, and chart of accounts through a REST API at gateway.prod.bill.com under the v3 path. Authentication is a session token, not OAuth2: a login call with the developer key, organization id, and account credentials returns a sessionId that is sent on every request and expires after 35 minutes of inactivity. BILL does support real webhooks for events such as bill.created and payment.updated, signed with HMAC-SHA256 in the x-bill-sha-signature header. BILL is accounts payable and receivable focused and does not support purchase orders.

What moves between them

Vendors and approved bills move from Sage 50 into BILL so the payable can be paid in the cloud. ml-connector reads new and changed Sage 50 vendors and purchase invoices on each poll and creates or updates the matching BILL vendor and bill records. Payment status flows the other direction: when BILL marks a payment complete, ml-connector records that payment against the matching purchase invoice in Sage 50 so the bill is closed in the ledger. Chart of accounts and GL account references are aligned so each bill line in BILL maps to a valid Sage 50 GL account. The cadence is a scheduled poll of Sage 50, typically every 5 to 15 minutes, while BILL payment events can arrive by webhook in near real time.

How ml-connector handles it

ml-connector runs a local agent on the Sage 50 machine that holds the Sage username and password encrypted and opens the company file through the SDK, while in the cloud it stores the BILL devKey and credentials encrypted and performs the BILL login to get a session token. Because the BILL session expires after 35 minutes of inactivity and returns a plain auth error rather than a clear expiry code, ml-connector treats any 401 as a signal to log in again and retry. Sage 50 has no webhooks, so vendor and bill changes are found by polling modified records since the last sync; BILL payment events are received by webhook where enabled and otherwise confirmed by a GET call. Vendors are matched by name and bills by invoice number, since Sage 50 assigns its own internal ids and BILL has no idempotency key, so ml-connector keeps a mapping table to avoid creating duplicates. BILL allows only three concurrent requests per organization, so calls are queued and backed off on the BDC_1144 and BDC_1322 rate limit codes. The SDK takes an exclusive lock on the company file, so the agent uses a dedicated Sage user and runs when the file is not open interactively. Purchase orders stay in Sage 50, since BILL does not model them. Every record carries a full audit trail and can be replayed if a downstream call fails.

A real-world example

A 40-person construction subcontractor keeps its books in Sage 50 on an office Windows machine and recently moved bill approvals and vendor payments to BILL so partners can approve and pay from anywhere. Before the integration, an office manager entered each subcontractor and supplier bill into BILL by hand, then re-keyed every payment back into Sage 50 so the ledger matched the bank, which left payables out of sync for days and made month-end reconciliation slow. With Sage 50 and BILL connected, approved bills and vendors flow from Sage 50 into BILL automatically and each completed payment posts straight back against the right purchase invoice in Sage 50. The books reflect what BILL paid without manual re-entry, and reconciliation starts with payables already matched.

What you can do

  • Sync vendors and approved bills from Sage 50 into BILL so payables can be approved and paid in the cloud.
  • Record BILL payment status against the matching Sage 50 purchase invoice so each bill closes in the ledger.
  • Match vendors by name and bills by invoice number, with a mapping table that prevents duplicate records.
  • Bridge the local Sage 50 agent credentials and the BILL session login, refreshing the BILL token when it expires.
  • Poll Sage 50 on a schedule since it has no webhooks, with retries, rate-limit backoff, and a full audit trail on every record.

Questions

Which direction does data move between Sage 50 and BILL?
Vendors and approved bills move from Sage 50 into BILL, and payment status moves back from BILL into Sage 50. When BILL completes a payment, ml-connector records it against the matching Sage 50 purchase invoice so the bill is closed in the ledger. Purchase orders stay in Sage 50, since BILL does not support them.
Why does Sage 50 need a local agent instead of a cloud connection?
Sage 50 is desktop software with no cloud REST API. Integration runs through a small Windows agent that uses the Sage 50 SDK on the same machine as the company data files. The agent syncs to ml-connector over HTTPS, so the machine must stay on and logged in for syncs to run.
How does the integration deal with BILL session expiry and concurrency limits?
BILL sessions expire after 35 minutes of inactivity and return a generic auth error, so ml-connector treats any 401 as a prompt to log in again and retry the call. BILL also allows only three concurrent requests per organization, so requests are queued and backed off on the documented rate limit codes. This keeps the sync within BILL's limits without dropping records.

Related integrations

Connect Sage 50 and BILL

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

Get started