Freshh for Craft CMS

For Craft Commerce 5

Your Commerce orders, already in FreshBooks

Every month the same job: export the orders, work out what the tax actually was, and retype it into FreshBooks. Freshh does it as the orders complete — the invoice, the client and the payment — and checks the arithmetic before it sends anything.

Freshh

Rehearses before it sends

A dry run needs no FreshBooks connection at all. Point it at two years of orders and see exactly what would be created, and whether every invoice balances, before you connect anything.

bash
$ php craft freshh/sync/push --dry-run --limit=3

  1042 → invoice INV-1042, USD 124.33 (order total 124.33)
  1043 → invoice INV-1043, USD  25.00 (order total  25.00)
  1044 → invoice INV-1044, USD  60.00 (order total  60.00)

Dry run: nothing was sent.

# Then, once you are happy with the mapping:
$ php craft freshh/sync/push --limit=500

Features

An accounting bridge is only worth having if you can trust the numbers on the other side of it. Most of Freshh is about earning that.

Money that maps exactly

FreshBooks multiplies quantity by unit cost and adds percentages. Commerce stores totals and tax amounts. Freshh does the translation — including tax Commerce included in the price, which a FreshBooks line has no concept of.

  • Tax percentages come from the Commerce rate itself, not derived and rounded
  • Inclusive tax is split into net price plus rate — same total, tax still visible in FreshBooks' reports

Checks the total before it sends

Freshh computes the total FreshBooks will arrive at and compares it with what the customer actually paid. A cent of drift gets a rounding line. Anything larger is refused, with a notice naming the adjustment that could not be expressed.

  • An invoice a pound out is worse than no invoice — nobody notices until a reconciliation fails months later

Never invoiced twice

FreshBooks accepts no idempotency key, and a queue worker can die between creating an invoice and recording that it did. Freshh claims the order first, then asks FreshBooks whether the invoice already exists, and adopts it if so.

  • A unique index means two queue workers cannot both own one order
  • A retry after a crash picks up the invoice it already made

Payments and refunds, both ways

Every successful transaction becomes a FreshBooks payment against the invoice, with the gateway reference kept so a chargeback stays traceable. Every refund becomes a credit note — the instrument FreshBooks' own documentation points at.

Nothing happens during checkout

Syncing is queued, always. A FreshBooks outage cannot fail an order, and no shopper ever waits on somebody else's API. Token refresh runs under a mutex, because FreshBooks refresh tokens are one-time-use and two workers refreshing at once would kill the connection.

You can see what it will do

Every order has a preview, and the settings screen previews your latest one. Both run the same code the queue job runs, so the payload you are shown is byte-for-byte what FreshBooks receives — with both totals side by side.

  • Every call is logged with its payload, status and duration; tokens are redacted

Frequently Asked Questions

The questions worth answering before you install it.

Stop retyping your orders

Freshh is $79 for one Craft installation. Install it, run a dry run against your real orders, and see the mapping before you connect anything.