Freshh for Craft CMS

FAQ

What does Freshh actually send?

A completed Commerce order becomes a FreshBooks invoice against a FreshBooks client, its successful transactions become payments, and its refunds become credit notes. Optionally, purchasables are mirrored into the FreshBooks item catalogue.

Can it slow down or break checkout?

No. Everything that talks to FreshBooks happens in a queue job. A FreshBooks outage cannot fail an order, and no shopper ever waits on someone else's API.

Will I get duplicate invoices?

Not from a retry. FreshBooks accepts no idempotency key, so Freshh claims a row keyed on the order, and if a previous attempt created the invoice but died before recording it, the next attempt finds it by invoice number and adopts it.

What happens to orders placed before I installed it?

Nothing, until you ask. freshh/sync/push --limit=500 backfills them, and --dry-run rehearses first without needing a connection at all.

How is tax handled?

As a percentage on each line, taken from the Commerce tax rate's own snapshot where there is one and derived from the amount where there is not. FreshBooks allows two taxes per line; a third and fourth are summed into one and the sync says so.

What about tax included in the price?

A FreshBooks line has no inclusive-tax concept. By default Freshh sends the net unit price plus the rate, which comes to the same total and keeps the tax visible in FreshBooks' reports. You can also tell it to leave the tax in the price and show none.

What if the invoice does not match the order total?

Freshh computes the total FreshBooks will arrive at and compares it before sending. A gap of cents gets a rounding line; anything larger is refused, with a notice saying which adjustment could not be expressed. That refusal is deliberate — an invoice that is a pound out is worse than no invoice.

Does it handle multiple currencies?

The invoice is created in the order's currency and the payment recorded in the transaction's. If your FreshBooks account is not set up for that currency, FreshBooks will say so and the error appears in the log.

Does it work with guest checkouts?

Yes. Clients are matched on email rather than on a Craft user, so three guest orders from one address are one FreshBooks client.

Can FreshBooks change my order statuses?

Only if you ask it to. Status mapping is off by default; turning it on lets a paid invoice move a Commerce order, which also fires Commerce's status emails.

Do I need webhooks?

Only to get invoice status back into Craft. Pushing orders works without them. If FreshBooks cannot reach your site, freshh/sync/pull does the same job on a schedule.

Is the webhook endpoint safe to expose?

Yes. It verifies the HMAC signature, and then throws the payload away and re-fetches the resource from the API. A forged callback costs one wasted API call and cannot change a number in your books.

Where are my tokens stored?

Encrypted with Craft's security key, in the database — not in project config, which is committed to version control. They never appear in the log; every payload is redacted on the way in.

Can I add my own fields to the invoice?

Yes — Mapper::EVENT_AFTER_BUILD_INVOICE fires before anything is sent, and totals are recomputed afterwards so an added line cannot quietly unbalance the invoice.

Does it sync expenses, projects or time tracking?

No. Freshh covers the Commerce side of FreshBooks — invoices, clients, payments, credit notes and items. Expenses, projects, time entries, estimates, bills and journal entries are out of scope.

Can two sites share one FreshBooks app?

They should not. FreshBooks allows one valid refresh token per user per application, so two sites sharing a client ID will keep invalidating each other's connection. Give each site its own app.

Which versions are supported?

Craft CMS 5.3+, Craft Commerce 5.0+, PHP 8.2+.