ml-connector
FreshBooksBILL

FreshBooks and BILL integration

FreshBooks keeps the books for small businesses and freelancers. BILL runs the vendor payments. Connecting the two means a bill entered in FreshBooks can be paid in BILL without re-keying, and the payment that clears in BILL is written back so the FreshBooks bill shows as paid. ml-connector creates vendors and bills in BILL from FreshBooks records, then records each BILL payment against the matching FreshBooks bill. It handles the very different login methods on each side and moves the data on a schedule you control.

How FreshBooks works

FreshBooks exposes clients, invoices, expenses, AP bills, bill vendors, invoice and bill payments, items, journal entries, and the chart of accounts through its REST accounting API. Every call uses an OAuth 2.0 access token and must include an account_id, with a separate business_id for time-tracking endpoints, both read from the users/me identity endpoint after consent. Reads are offset-paginated at up to 100 records per page. FreshBooks can also push events such as bill.create and payment.create by webhook signed with an HMAC-SHA256 header, but delivery latency is not guaranteed, so polling backs it up.

How BILL works

BILL exposes vendors, AP bills, AP payments, recurring bills, vendor credits, AR customers and invoices, GL accounts, and accounting classifications such as departments and locations through its v3 REST API. Authentication is a session token: the connector posts a devKey with the org username, password, and organizationId to the login endpoint and receives a sessionId that expires after 35 minutes of inactivity. Reads are page-based at up to 100 records. BILL can push events like bill.created and payment.updated by webhook signed with HMAC-SHA256, and limits each org to three concurrent requests.

What moves between them

The main flow runs from FreshBooks into BILL. ml-connector reads the AP bills and bill vendors a customer enters in FreshBooks and creates or updates the matching vendors and bills in BILL, mapping each bill line to a BILL GL account, so the bill is ready to be paid there. Payment status flows back the other direction: ml-connector reads BILL payments and records each settled amount against the original FreshBooks bill as a bill payment, so the FreshBooks balance reflects what BILL has paid. Vendor records are aligned so the same supplier is not duplicated. Cadence follows a schedule you set, with BILL payment webhooks triggering the write-back sooner where they arrive.

How ml-connector handles it

ml-connector stores both credential sets encrypted. For FreshBooks it holds the OAuth client and refresh token and gets a fresh access token when a call returns 401, and it keeps the account_id on hand because almost every FreshBooks path requires it. For BILL it logs in with the devKey, username, password, and organizationId, caches the sessionId, and logs in again when a call fails on an expired session, since BILL returns a generic auth error rather than a clear expiry code. A FreshBooks vendor maps to a BILL vendor and a FreshBooks bill maps to a BILL bill, with bill lines mapped to BILL GL accounts. Because BILL allows only three concurrent requests per org, ml-connector limits parallelism and backs off on the BDC_1144 and BDC_1322 rate codes. Neither side offers a real idempotency key, so bills are matched on bill_number and vendor before any create to avoid duplicates, and BILL entity IDs are stored so a record is never created twice. FreshBooks bills start linked to a vendor, so the vendor is created or found first. Webhook latency on the FreshBooks side is not guaranteed, so a scheduled poll backs up every event.

A real-world example

A ten-person marketing agency keeps its books in FreshBooks, where the owner enters vendor bills for contractors, software, and ad spend. Paying those bills meant logging into bank portals and cutting checks by hand, then going back into FreshBooks later to mark each bill paid, which often slipped. With FreshBooks and BILL connected, each approved bill flows into BILL where payments run by ACH or check, and once a payment clears in BILL it is recorded against the FreshBooks bill automatically. The owner schedules payments in one place and the books stay current without the manual mark-as-paid step.

What you can do

  • Create vendors and AP bills in BILL from the bills and bill vendors entered in FreshBooks.
  • Record each settled BILL payment against the matching FreshBooks bill so balances stay current.
  • Map FreshBooks chart-of-accounts entries to BILL GL accounts so every bill line lands on a valid account.
  • Bridge the FreshBooks OAuth token and the BILL devKey session login, refreshing each before it expires.
  • Match bills on bill number and vendor before creating, so payments are never duplicated across the two systems.

Questions

Which direction does data move between FreshBooks and BILL?
The main flow is FreshBooks into BILL. AP bills and vendors move from FreshBooks into BILL so payments can be scheduled there. Payment status flows back the other way, with each cleared BILL payment recorded against the original FreshBooks bill as a bill payment.
How does the integration handle the two different logins?
FreshBooks uses an OAuth 2.0 access token that ml-connector refreshes when a call returns 401, and BILL uses a session token obtained by posting the devKey and org credentials to its login endpoint. ml-connector stores both encrypted, caches the BILL sessionId, and logs in again when a request fails on an expired session, since BILL reports expiry as a generic auth error rather than a clear code.
How are duplicate vendors and bills avoided?
Neither FreshBooks nor BILL offers a native idempotency key, so ml-connector matches on natural keys before any create. A bill is matched on its bill number and vendor, and the BILL entity IDs returned on create are stored so the same record is never created twice. FreshBooks bills are always linked to a vendor, so the vendor is created or found first.

Related integrations

Connect FreshBooks and BILL

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

Get started