PHPackages                             shukyusof/qb-sdk - 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. shukyusof/qb-sdk

ActiveLibrary[API Development](/categories/api)

shukyusof/qb-sdk
================

Laravel SDK for QuickBooks Online (QBO) — OAuth2, multi-company, multi-tenant

v1.2.0(2mo ago)07↓66.7%MITPHPPHP ^8.1

Since Feb 20Pushed 2mo agoCompare

[ Source](https://github.com/shukriYusof/quickbook-sdk)[ Packagist](https://packagist.org/packages/shukyusof/qb-sdk)[ RSS](/packages/shukyusof-qb-sdk/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (10)Versions (5)Used By (0)

QuickBooks Online SDK for Laravel
=================================

[](#quickbooks-online-sdk-for-laravel)

A Laravel-first Composer SDK for QuickBooks Online (QBO). Supports single-company apps, multi-company setups, and full SaaS multi-tenant platforms from the same codebase — with driver-based token storage, flexible company resolution, and automatic OAuth2 token refresh.

---

Requirements
------------

[](#requirements)

VersionPHP8.1+Laravel10.x / 11.x / 12.x---

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

[](#installation)

```
composer require shukyusof/qb-sdk
```

Laravel auto-discovers the service provider. To publish the config and migrations:

```
php artisan vendor:publish --tag=quickbooks-config
php artisan vendor:publish --tag=quickbooks-migrations
php artisan vendor:publish --tag=quickbooks-stubs
php artisan migrate
```

---

Configuration
-------------

[](#configuration)

Add these to your `.env`:

```
QUICKBOOKS_CLIENT_ID=your_client_id
QUICKBOOKS_CLIENT_SECRET=your_client_secret
QUICKBOOKS_REDIRECT_URI=https://yourapp.com/quickbooks/callback
QUICKBOOKS_ENVIRONMENT=production          # or sandbox
QUICKBOOKS_TOKEN_STORE=database            # or cache
QUICKBOOKS_COMPANY_RESOLVER=model          # env | model | static | chain

# Single-company shorthand
QUICKBOOKS_DEFAULT_COMPANY=your-qb-company-uuid

# Optional tuning
QUICKBOOKS_TIMEOUT=30
QUICKBOOKS_RETRY_TIMES=3
QUICKBOOKS_RETRY_SLEEP=1000
```

---

Quickstart
----------

[](#quickstart)

### 1. Register a company source (one-time)

[](#1-register-a-company-source-one-time)

```
use App\Models\QuickBooksCompany;

$company = QuickBooksCompany::registerSource($yourModel, tenantId: null, labelColumn: 'name');
// $company->qb_company_id  →  UUID used everywhere in the SDK
```

### 2. Redirect the user to QuickBooks to authorize

[](#2-redirect-the-user-to-quickbooks-to-authorize)

```
use QuickBooks\SDK\Laravel\Facades\QuickBooks;

$url = QuickBooks::getAuthorizationUrl($company->qb_company_id);
return redirect($url);
```

### 3. Handle the OAuth callback

[](#3-handle-the-oauth-callback)

```
public function callback(Request $request)
{
    $client = QuickBooks::handleCallback(
        $request->get('code'),
        $request->get('realmId'),
        $request->get('state')
    );

    // $client is ready to use immediately
}
```

### 4. Use the client

[](#4-use-the-client)

```
$client = QuickBooks::company($qbCompanyId);

// or for single-company apps:
$client = QuickBooks::client();
```

---

Available Resources
-------------------

[](#available-resources)

All resources inherit `all()`, `find($id)`, `create($payload)`, `update($payload)`, `sparseUpdate($payload)`, and `query($sql)` from `BaseResource`.

### Invoices

[](#invoices)

```
$client->invoices()->all();
$client->invoices()->find('123');
$client->invoices()->overdue();             // Balance > 0
$client->invoices()->create([...]);
$client->invoices()->sparseUpdate(['Id' => '1', 'SyncToken' => '0', 'PrivateNote' => 'x']);
```

### Customers

[](#customers)

```
$client->customers()->all();
$client->customers()->active();
$client->customers()->findByEmail('user@example.com');
$client->customers()->create([...]);
```

### Payments

[](#payments)

```
$client->payments()->all();
$client->payments()->find('456');
$client->payments()->create([...]);
```

### Accounts (Chart of Accounts)

[](#accounts-chart-of-accounts)

```
$client->accounts()->all();
$client->accounts()->getByType('Expense');
// Valid types: Bank, Other Current Asset, Fixed Asset, Other Asset,
//   Accounts Receivable, Equity, Expense, Other Expense,
//   Cost of Goods Sold, Accounts Payable, Credit Card,
//   Long Term Liability, Other Current Liability, Income, Other Income
```

### Vendors

[](#vendors)

```
$client->vendors()->all();
$client->vendors()->active();
$client->vendors()->findByName('Acme Supplies');
$client->vendors()->create([...]);
```

### Bills (Accounts Payable)

[](#bills-accounts-payable)

```
$client->bills()->all();
$client->bills()->unpaid();                 // Balance > 0
$client->bills()->forVendor($vendorId);
$client->bills()->create([...]);
```

### Purchase Orders

[](#purchase-orders)

```
$client->purchaseOrders()->all();
$client->purchaseOrders()->open();          // POStatus = 'Open'
$client->purchaseOrders()->forVendor($vendorId);
$client->purchaseOrders()->create([...]);
```

### Estimates

[](#estimates)

```
$client->estimates()->all();
$client->estimates()->pending();            // TxnStatus = 'Pending'
$client->estimates()->accepted();           // TxnStatus = 'Accepted'
$client->estimates()->forCustomer($customerId);
$client->estimates()->create([...]);
```

### Credit Memos

[](#credit-memos)

```
$client->creditMemos()->all();
$client->creditMemos()->unapplied();        // Balance > 0
$client->creditMemos()->forCustomer($customerId);
$client->creditMemos()->create([...]);
```

### Employees

[](#employees)

```
$client->employees()->all();
$client->employees()->active();
$client->employees()->findByName('Jane Smith');
$client->employees()->create([...]);
```

---

Calling Resources Not Covered by a Typed Class
----------------------------------------------

[](#calling-resources-not-covered-by-a-typed-class)

The SDK ships typed classes for the most commonly used QBO entities. For everything else — `JournalEntry`, `TaxRate`, `TaxCode`, `CompanyInfo`, `Department`, `Class`, `Item`, `RefundReceipt`, `SalesReceipt`, `Transfer`, `Deposit`, and any other QBO entity — use the raw client methods directly.

### `get($uri, $query = [])`

[](#geturi-query--)

```
// Fetch a single record
$client->get('taxrate/1');
$client->get('item/42');
$client->get('department/5');

// Fetch with query parameters
$client->get('companyinfo/' . $realmId);
```

### `post($uri, $payload = [])`

[](#posturi-payload--)

```
// Create any entity
$client->post('journalentry', [
    'Line' => [...],
    'CurrencyRef' => ['value' => 'USD'],
]);

// Create a sales receipt
$client->post('salesreceipt', [
    'CustomerRef' => ['value' => '1'],
    'Line' => [...],
]);
```

### `query($sql)`

[](#querysql)

QBO supports a SQL-like query language across all entities. Use this for any entity that supports querying:

```
// Journal entries
$client->query("SELECT * FROM JournalEntry WHERE DocNumber = 'JE-001'");

// Tax rates
$client->query("SELECT * FROM TaxRate WHERE Active = true");

// Items / products
$client->query("SELECT * FROM Item WHERE Type = 'Inventory'");
$client->query("SELECT * FROM Item WHERE Name LIKE '%Widget%'");

// Company info
$client->query("SELECT * FROM CompanyInfo");

// Departments
$client->query("SELECT * FROM Department WHERE Active = true");

// Classes
$client->query("SELECT * FROM Class WHERE Active = true");

// Deposits
$client->query("SELECT * FROM Deposit WHERE TotalAmt > '1000'");

// Sales receipts
$client->query("SELECT * FROM SalesReceipt WHERE Balance > '0'");

// Refund receipts
$client->query("SELECT * FROM RefundReceipt");

// Transfers
$client->query("SELECT * FROM Transfer");

// Time activities
$client->query("SELECT * FROM TimeActivity WHERE BillableStatus = 'Billable'");
```

> **Note:** String values in QBO query language must be wrapped in single quotes. Numeric comparisons do not require quotes.

---

Exception Handling
------------------

[](#exception-handling)

```
use QuickBooks\SDK\Exceptions\AuthenticationException;
use QuickBooks\SDK\Exceptions\RateLimitException;
use QuickBooks\SDK\Exceptions\ApiException;
use QuickBooks\SDK\Exceptions\CompanyNotFoundException;
use QuickBooks\SDK\Exceptions\QuickBooksException;

try {
    $invoices = QuickBooks::company($id)->invoices()->all();
} catch (RateLimitException $e) {
    // HTTP 429 — back off and retry later
} catch (AuthenticationException $e) {
    // OAuth expired or invalid — re-authorize the company
} catch (CompanyNotFoundException $e) {
    // Unknown qb_company_id
} catch (ApiException $e) {
    // Other HTTP error (404, 500, etc.)
    // $e->getCode() returns the HTTP status code
} catch (QuickBooksException $e) {
    // Catch-all for any SDK exception
}
```

---

Multi-Company
-------------

[](#multi-company)

```
// Check connection state
QuickBooks::isConnected($qbCompanyId);   // bool
QuickBooks::connectionStatus();           // ['uuid' => bool, ...]

// Iterate all connected companies
foreach (QuickBooks::allCompanies() as $qbCompanyId => $client) {
    $client->invoices()->overdue();
}

// Disconnect
QuickBooks::disconnectCompany($qbCompanyId);
```

---

Multi-Tenancy
-------------

[](#multi-tenancy)

Set the tenant context before resolving a client — typically in middleware:

```
use QuickBooks\SDK\Tenant\TenantContext;

app(TenantContext::class)->setTenantId($request->user()->tenant_id);
```

Then use the SDK normally. All token reads and writes are automatically scoped to the active tenant.

---

Token Storage Drivers
---------------------

[](#token-storage-drivers)

DriverConfigUse case`database``QUICKBOOKS_TOKEN_STORE=database`Default, persistent`cache``QUICKBOOKS_TOKEN_STORE=cache`Redis/Memcached, TTL-aware`tenant_database``QUICKBOOKS_TOKEN_STORE=tenant_database`Multi-tenant DB isolation---

Company Resolver Drivers
------------------------

[](#company-resolver-drivers)

DriverConfigUse case`model``QUICKBOOKS_COMPANY_RESOLVER=model`Reads from `quickbooks_companies` table`env``QUICKBOOKS_COMPANY_RESOLVER=env`Comma-separated UUIDs in `QUICKBOOKS_COMPANIES``static``QUICKBOOKS_COMPANY_RESOLVER=static`Hardcoded array, useful for testing`chain``QUICKBOOKS_COMPANY_RESOLVER=chain`Merges multiple resolvers with deduplication---

Artisan Commands
----------------

[](#artisan-commands)

```
# Register all records from a model as QBO companies
php artisan qb:register "App\Models\Company" --label=name

# With tenant scoping
php artisan qb:register "App\Models\Company" --label=name --tenant=tenant-uuid

# With a where-filter
php artisan qb:register "App\Models\Company" --label=name --filter="is_active=1"
```

---

License
-------

[](#license)

MIT

###  Health Score

36

—

LowBetter than 82% of packages

Maintenance83

Actively maintained with recent releases

Popularity5

Limited adoption so far

Community2

Small or concentrated contributor base

Maturity46

Maturing project, gaining track record

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 ~1 days

Total

4

Last Release

84d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/7092a8c917231a2f7a37f43f9a4a8fdd759e69fb8e499dfb02797eff8753cda4?d=identicon)[shukriYusof](/maintainers/shukriYusof)

---

Tags

laraveloauth2Accountingquickbooksintuitqbo

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/shukyusof-qb-sdk/health.svg)

```
[![Health](https://phpackages.com/badges/shukyusof-qb-sdk/health.svg)](https://phpackages.com/packages/shukyusof-qb-sdk)
```

###  Alternatives

[laravel/pulse

Laravel Pulse is a real-time application performance monitoring tool and dashboard for your Laravel application.

1.7k12.1M99](/packages/laravel-pulse)[vluzrmos/slack-api

Wrapper for Slack.com WEB API.

102589.1k3](/packages/vluzrmos-slack-api)[roots/acorn

Framework for Roots WordPress projects built with Laravel components.

9682.1M97](/packages/roots-acorn)[laravel/cashier-paddle

Cashier Paddle provides an expressive, fluent interface to Paddle's subscription billing services.

264778.4k3](/packages/laravel-cashier-paddle)[smodav/mpesa

M-Pesa API implementation

16363.7k1](/packages/smodav-mpesa)[flarum/core

Delightfully simple forum software.

211.3M1.9k](/packages/flarum-core)

PHPackages © 2026

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