PHPackages                             chrisjohnleah/sage-business-cloud-accounting-api - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. chrisjohnleah/sage-business-cloud-accounting-api

ActiveLibrary[API Development](/categories/api)

chrisjohnleah/sage-business-cloud-accounting-api
================================================

Framework-agnostic PHP SDK for the Sage Business Cloud Accounting API (v3.1), built on Saloon.

v0.1.2(1mo ago)0312MITPHPPHP ^8.3CI passing

Since May 30Pushed 1mo agoCompare

[ Source](https://github.com/chrisjohnleah/sage-business-cloud-accounting-api)[ Packagist](https://packagist.org/packages/chrisjohnleah/sage-business-cloud-accounting-api)[ Docs](https://github.com/chrisjohnleah/sage-business-cloud-accounting-api)[ RSS](/packages/chrisjohnleah-sage-business-cloud-accounting-api/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (2)Dependencies (8)Versions (4)Used By (2)

Sage Business Cloud Accounting API — PHP SDK
============================================

[](#sage-business-cloud-accounting-api--php-sdk)

[![CI](https://github.com/chrisjohnleah/sage-business-cloud-accounting-api/actions/workflows/ci.yml/badge.svg)](https://github.com/chrisjohnleah/sage-business-cloud-accounting-api/actions/workflows/ci.yml)[![Packagist Version](https://camo.githubusercontent.com/2463ef4471c7723baa9ff8134237b2bd303b1e4dd867a8de6301c11d997bb961/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f63687269736a6f686e6c6561682f736167652d627573696e6573732d636c6f75642d6163636f756e74696e672d6170692e737667)](https://packagist.org/packages/chrisjohnleah/sage-business-cloud-accounting-api)[![Total Downloads](https://camo.githubusercontent.com/6064a8fdd3ef1618d5c2b8c937953eb70bc3eed97834b674c55f85394251dbeb/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f63687269736a6f686e6c6561682f736167652d627573696e6573732d636c6f75642d6163636f756e74696e672d6170692e737667)](https://packagist.org/packages/chrisjohnleah/sage-business-cloud-accounting-api)[![PHP Version](https://camo.githubusercontent.com/c375299e3faa2f124e3b88007fbb3226750334c09ad41427e4cdbaae77430277/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f63687269736a6f686e6c6561682f736167652d627573696e6573732d636c6f75642d6163636f756e74696e672d6170692e737667)](https://packagist.org/packages/chrisjohnleah/sage-business-cloud-accounting-api)[![License: MIT](https://camo.githubusercontent.com/7013272bd27ece47364536a221edb554cd69683b68a46fc0ee96881174c4214c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75652e737667)](LICENSE)

A modern, framework-agnostic PHP SDK for the [Sage Business Cloud Accounting API (v3.1)](https://developer.sage.com/accounting/), built on [Saloon](https://docs.saloon.dev). Typed responses, OAuth2 with rotating-refresh handling, `X-Business` targeting, automatic `$next` pagination, and rate-limit / 429 backoff — all baked in.

> **Using Laravel?** Reach for the companion bridge [`chrisjohnleah/sage-business-cloud-accounting-api-laravel`](https://github.com/chrisjohnleah/sage-business-cloud-accounting-api-laravel)for a service provider, an Eloquent token store, and `sage:connect` / `sage:sync` commands.

Why this package
----------------

[](#why-this-package)

The Sage Accounting API has sharp edges that this SDK smooths over for you:

Sage quirkWhat the SDK does**5-minute access tokens**Refreshes proactively before expiry**Rotating refresh tokens** (single-use)Surfaces the rotated token so you can persist it**Mandatory `X-Business` header**Applied automatically once a business is selected**No webhooks**First-class incremental polling via `updated_or_created_since` / `deleted_since`**Body-based `$next` pagination**Iterated transparently — `foreach` over every record**Rate limits** (100/min per company)Honours `429 Retry-After` and backs off exponentiallyRequirements
------------

[](#requirements)

- PHP 8.3+
- A Sage Developer app (OAuth2 client id + secret) — register at [developerselfservice.sageone.com](https://developerselfservice.sageone.com)

Installation
------------

[](#installation)

```
composer require chrisjohnleah/sage-business-cloud-accounting-api
```

Quick start
-----------

[](#quick-start)

```
use ChrisJohnLeah\SageAccounting\Auth\ArrayTokenStore;
use ChrisJohnLeah\SageAccounting\Sage;
use ChrisJohnLeah\SageAccounting\SageConnector;

$connector = new SageConnector(
    clientId: getenv('SAGE_CLIENT_ID'),
    clientSecret: getenv('SAGE_CLIENT_SECRET'),
    redirectUri: 'https://your-app.test/oauth/sage/callback',
    scopes: ['readonly'], // or ['full_access']
);

// Bring your own persistence (DB, cache…) by implementing TokenStore.
// ArrayTokenStore keeps tokens in memory — handy for scripts and tests.
$sage = new Sage($connector, new ArrayTokenStore);
```

### 1. Send the user to Sage to authorise

[](#1-send-the-user-to-sage-to-authorise)

```
$url   = $sage->authorizationUrl();   // redirect the user here
$state = $sage->generatedState();     // persist this (session/cache) for the callback
```

### 2. Handle the callback

[](#2-handle-the-callback)

```
$sage->exchangeCode($_GET['code'], $_GET['state'], $expectedState: $state);
$sage->resolveBusiness();             // selects + remembers the business to target
```

### 3. Read data (auto-refreshes, auto-paginates)

[](#3-read-data-auto-refreshes-auto-paginates)

```
// Every supplier bill updated since a timestamp — typed, across all pages.
$bills = $sage->purchaseInvoices()->list([
    'updated_or_created_since' => '2026-05-01T00:00:00Z',
]);

foreach ($bills as $invoice) {
    printf(
        "%s owes %.2f, due %s [%s]\n",
        $invoice->contactName,
        $invoice->outstandingAmount ?? 0.0,
        $invoice->dueDate?->format('Y-m-d') ?? 'n/a',
        $invoice->status?->displayedAs ?? 'unknown',
    );
}

// Suppliers
foreach ($sage->contacts()->list(['contact_type_id' => 'VENDOR']) as $contact) {
    echo $contact->name, ' connector()`:

```
use ChrisJohnLeah\SageAccounting\Requests\LedgerAccounts\GetLedgerAccounts;
use ChrisJohnLeah\SageAccounting\Requests\Contacts\PostContacts;

$ledgers = $sage->connector()->send(new GetLedgerAccounts(['attributes' => 'all']))->dto();
$created = $sage->connector()->send(new PostContacts(['contact' => [/* ... */]]))->dto();
```

### Regenerating from the spec

[](#regenerating-from-the-spec)

```
php tools/generate.php   # re-reads resources/openapi/sage-accounting-3.1.0.json
```

The hand-crafted core (connector, OAuth, paginator, client, `Reference`/`Paginated`) is never touched — only the leaf DTOs and request classes are generated.

Testing
-------

[](#testing)

```
composer test      # Pest
composer analyse   # PHPStan (max)
composer lint      # Pint --test
composer check     # all three
```

Tests never hit the network — every request is faked with Saloon's `MockClient`.

Contributing
------------

[](#contributing)

Issues and PRs welcome — see [CONTRIBUTING.md](CONTRIBUTING.md). Please report security issues privately per [SECURITY.md](SECURITY.md).

Licence
-------

[](#licence)

MIT © [Chris John Leah](https://github.com/chrisjohnleah). See [LICENSE](LICENSE).

> Not affiliated with or endorsed by The Sage Group plc. "Sage" is a trademark of its respective owner.

###  Health Score

39

—

LowBetter than 84% of packages

Maintenance89

Actively maintained with recent releases

Popularity10

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity41

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

3

Last Release

55d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/ec2ce54c81968f6fc293587599bbaaa4221e303eec07cd2a50de1d99a6f0f2a4?d=identicon)[chrisjohnleah](/maintainers/chrisjohnleah)

---

Top Contributors

[![chrisjohnleah](https://avatars.githubusercontent.com/u/959104?v=4)](https://github.com/chrisjohnleah "chrisjohnleah (8 commits)")

---

Tags

accountingapi-clientbookkeepingoauth2phpphp-sdkrest-apisagesage-accountingsage-business-cloudsaloonsaloonphpapisdkoauth2saloonAccountingsagesage-business-cloud

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

Type Coverage Yes

### Embed Badge

![Health badge](/badges/chrisjohnleah-sage-business-cloud-accounting-api/health.svg)

```
[![Health](https://phpackages.com/badges/chrisjohnleah-sage-business-cloud-accounting-api/health.svg)](https://phpackages.com/packages/chrisjohnleah-sage-business-cloud-accounting-api)
```

###  Alternatives

[saloonphp/laravel-plugin

The official Laravel plugin for Saloon

807.1M211](/packages/saloonphp-laravel-plugin)[ohdearapp/ohdear-php-sdk

An SDK to easily work with the Oh Dear API

743.0M17](/packages/ohdearapp-ohdear-php-sdk)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
