Sager for Craft CMS

Installation

Requirements

  • Craft CMS 5.3 or later
  • Craft Commerce 5.0 or later
  • PHP 8.2 or later, with the json extension
  • A Sage Business Cloud Accounting subscription, and a free account on Sage's developer portal
  • Craft's queue running, either on web requests (the default) or as a worker

No build step, and no runtime dependencies beyond Craft and Commerce.

Install

composer require justinholtweb/craft-sager
php craft plugin/install sager

Or find Sager in the Craft Plugin Store and install it from there.

Installing creates five tables: the Sage connection, the Sage documents Sager has created, the customer-to-contact links, per-order sync state, and the connection log. It adds no fields, entry types or Matrix blocks, so there's no content model to build.

Sager needs Commerce installed and enabled. If Commerce is missing or disabled, Sager still loads, but it listens for nothing and sends nothing.

Nothing is sent until you connect

A fresh install has no credentials and no connection. Orders keep completing as normal, and nothing is queued for Sage. Sager only starts sending once it's connected to a Sage business, and only orders completed after that point are sent automatically. Older orders wait until you send them. See Usage.

Your first fifteen minutes

Do this on your development site, where allowAdminChanges is on. Settings and mapping are saved to project config, so they deploy with the rest of your config.

  1. In Sage's developer portal, create an app. Leave the callback URL for a moment.
  2. In Craft, open Sager → Settings. Copy the Redirect URI and paste it into the app's callback URL in Sage. It has to match byte for byte.
  3. Put the app's client ID and secret in .env, and type $SAGE_CLIENT_ID and $SAGE_CLIENT_SECRET into Client ID and Client secret. The secret has to be an environment variable. See Configuration.
  4. Save, then press Connect to Sage and approve the connection in Sage.
  5. If your Sage login reaches more than one business, pick the one this store posts to and press Use this business. If it reaches one, Sager picks it for you.
  6. Sager sends you to Sager → Mapping. Choose at least a Sales ledger account and a Default tax rate, plus a Bank account if you're sending payments. Save.
  7. Open Sager → Overview. Every line of the Setup checklist should be ticked.
  8. Open a recent completed order in Sager → Orders and press Preview payload. That's the exact invoice Sage would receive. Check it, then press Send to Sage now.

Then deploy your project config, and connect production. See Configuration before you do: production needs its own connection, to the same Sage business.

Pricing

Sager has one edition. Everything in these docs is in it.

Sager
Price$129, then $99/year for updates
Orders as sales invoices, with per-line ledger accounts and tax rates✅
Customers as Sage contacts, found before they're created✅
Captured payments as contact payments, allocated against the invoice✅
Refunds as sales credit notes✅
Mapping screen built from your own Sage chart of accounts and tax rates✅
Per-tax-category and per-product-type mapping✅
Preview payload, built by the same code as the real push✅
Queue-driven sync with retries and Retry-After backoff✅
Connection log with full request and response bodies, secrets redacted✅
Order screen panel, order index and overview✅
Console commands and the craft.sager Twig variable✅

The licence covers one production install. Updates continue for as long as the licence is renewed. An expired licence keeps working. You just stop getting updates.

Uninstalling

Uninstalling drops all five tables. The Sage connection, the record of which documents Sager created, the customer-to-contact links and the log all go with them. Settings are removed from project config.

Nothing in Sage is touched. Invoices, contacts, payments and credit notes Sager created stay in your books. If you reinstall later, Sager has no memory of having sent anything, so Queue everything not sent would send those orders again. Sager does find existing contacts again by reference and email, but it can't tell that an invoice already exists in Sage.