FreshBooks and Adobe Commerce integration
FreshBooks keeps the books for small businesses. Adobe Commerce runs the online storefront. Connecting the two means every paid order on the storefront becomes an invoice in FreshBooks without anyone copying it across. Storefront customers line up with FreshBooks clients, captured payments mark the matching invoices paid, and refunds post as credit notes. ml-connector handles the very different APIs on each side and moves the records on a schedule you control.
What moves between them
The main flow runs from Adobe Commerce into FreshBooks. ml-connector reads paid orders and creates matching FreshBooks invoices, reads storefront customers and creates or updates FreshBooks clients, reads captured order payments and records them against the FreshBooks invoice, and reads credit memos and posts them as FreshBooks credit notes. Product SKUs can be mirrored into FreshBooks items so invoice lines reference known products. The cadence is a poll on the schedule you set, since Adobe Commerce webhooks are synchronous and FreshBooks webhook delivery is not guaranteed in real time. FreshBooks holds no e-commerce orders or purchase orders, so nothing is written back to the storefront.
How ml-connector handles it
ml-connector stores both credential sets encrypted. On the Adobe Commerce side it signs each request with OAuth 1.0a on PaaS or refreshes the IMS bearer token before its roughly 24-hour expiry on the Cloud Service, and it passes the store view code in the URL on PaaS or the scope header on SaaS. On the FreshBooks side it holds the OAuth refresh token, exchanges it for a fresh access token, and rotates the stored refresh token each time since FreshBooks invalidates the previous one. Clients are matched by email so a repeat buyer is not duplicated, and every order maps to a client before its invoice is created. FreshBooks invoices are created as Draft, so ml-connector marks them Sent so they appear in accounting reports. To avoid duplicate invoices it supplies the Adobe Commerce increment_id as the FreshBooks invoice_number, which also sidesteps the 409 conflicts that concurrent creates can cause. FreshBooks throttling returns HTTP 429, so it backs off and retries, and there is no sandbox on either side, so testing runs against a real FreshBooks trial account and an Adobe Commerce staging instance. Every record carries a full audit trail and can be replayed if a downstream call fails.
A real-world example
A small home-goods retailer with about 20 staff sells through an Adobe Commerce storefront and keeps its books in FreshBooks. Before the integration, a bookkeeper opened the storefront admin every morning, listed the prior day's paid orders, and typed each one into FreshBooks as an invoice, then matched the captured payment and the occasional refund by hand. Orders during a sale piled up faster than they could be entered, and customer names drifted out of step between the two systems. With FreshBooks and Adobe Commerce connected, each paid order arrives in FreshBooks as a sent invoice with the payment already applied, refunds post as credit notes, and the buyer is matched to an existing client by email. The bookkeeper reviews exceptions instead of re-keying every sale.
What you can do
- Create a FreshBooks invoice for every paid Adobe Commerce order, using the order number as the invoice number.
- Match Adobe Commerce customers to FreshBooks clients by email so repeat buyers are not duplicated.
- Record captured Adobe Commerce payments against the matching FreshBooks invoice and post credit memos as FreshBooks credit notes.
- Bridge Adobe Commerce OAuth 1.0a or IMS tokens and the FreshBooks OAuth refresh token plus account ID, rotating each as required.
- Poll on a schedule you control, marking new FreshBooks invoices as sent, with retries and a full audit trail on every record.
Questions
- Which direction does data move between FreshBooks and Adobe Commerce?
- The flow runs from Adobe Commerce into FreshBooks. Paid orders, customers, captured payments, and refunds move from the storefront into FreshBooks as invoices, clients, payments, and credit notes. FreshBooks has no e-commerce orders or purchase orders, so ml-connector does not write transactions back to the storefront.
- Why does the integration poll instead of relying on webhooks?
- Adobe Commerce webhooks are synchronous, meaning Commerce waits for your endpoint to respond before completing the order, which is not a safe place to do accounting work. FreshBooks does send outbound webhooks, but delivery can take from seconds to several minutes and is not guaranteed. For reliable accounting, ml-connector polls Adobe Commerce orders on the schedule you set rather than depending on a push.
- How are duplicate invoices in FreshBooks prevented?
- ml-connector supplies the Adobe Commerce increment_id, the human-readable order number, as the FreshBooks invoice_number. Because that value is unique per order, a re-run of the same order does not create a second invoice. This also avoids the 409 conflicts FreshBooks can return when invoice numbers are left unset, and every job is deduplicated on the connector side.
Related integrations
More FreshBooks integrations
Other systems that connect to Adobe Commerce
Connect FreshBooks and Adobe Commerce
Free to use. Add your credentials, ping your real systems, and see if we fit.
Get started