PHPackages                             jeffgreco13/laravel-wave - 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. jeffgreco13/laravel-wave

ActiveProject[API Development](/categories/api)

jeffgreco13/laravel-wave
========================

A wrapper to use the Wave GraphQL API in your Laravel apps.

2.0.0(2mo ago)03771MITPHPPHP ^8.2

Since Nov 22Pushed 2mo agoCompare

[ Source](https://github.com/jeffgreco13/laravel-wave)[ Packagist](https://packagist.org/packages/jeffgreco13/laravel-wave)[ RSS](/packages/jeffgreco13-laravel-wave/feed)WikiDiscussions 2.x Synced 1w ago

READMEChangelog (10)Dependencies (16)Versions (22)Used By (1)

laravel-wave
============

[](#laravel-wave)

A Laravel package for the [Wave Accounting](https://www.waveapps.com) GraphQL API. Query your Wave data, sync it to local Eloquent models, and manage customers, invoices, products, and more — all via queued jobs and Artisan commands.

---

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

[](#requirements)

- PHP 8.2+
- Laravel 11, 12, or 13
- A [Wave developer account](https://developer.waveapps.com) with an OAuth2 access token

---

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

[](#installation)

```
composer require jeffgreco13/laravel-wave
```

Publish the config file:

```
php artisan vendor:publish --tag=wave-config
```

Publish the migrations (optional — only needed if you want local sync):

```
php artisan vendor:publish --tag=wave-migrations
php artisan migrate
```

---

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

[](#configuration)

Add to your `.env`:

```
WAVE_ACCESS_TOKEN=your_oauth_token_here
WAVE_BUSINESS_ID=your_wave_business_uuid_here
```

Full `config/wave.php` reference:

```
return [
    'access_token' => env('WAVE_ACCESS_TOKEN'),
    'graphql_uri'  => env('WAVE_GRAPHQL_URI', 'https://gql.waveapps.com/graphql/public'),
    'business_id'  => env('WAVE_BUSINESS_ID'),

    // Override with your own Eloquent models (see "Custom Models" below)
    'models' => [
        'customer'  => \Jeffgreco13\Wave\Models\WaveCustomer::class,
        'invoice'   => \Jeffgreco13\Wave\Models\WaveInvoice::class,
        'product'   => \Jeffgreco13\Wave\Models\WaveProduct::class,
        'sales_tax' => \Jeffgreco13\Wave\Models\WaveSalesTax::class,
        'vendor'    => \Jeffgreco13\Wave\Models\WaveVendor::class,
        'business'  => \Jeffgreco13\Wave\Models\WaveBusiness::class,
        'account'   => \Jeffgreco13\Wave\Models\WaveAccount::class,
    ],

    'sync' => [
        'chunk_size' => 150, // records per page during sync
    ],
];
```

---

Basic Usage
-----------

[](#basic-usage)

Inject `WaveService` or resolve it from the container:

```
use Jeffgreco13\Wave\WaveService;

class InvoiceController extends Controller
{
    public function __construct(protected WaveService $wave) {}

    public function index()
    {
        // Returns a Collection of Node objects
        return $this->wave->getCustomers(['page' => 1, 'pageSize' => 20]);
    }
}
```

Nodes support both array and property access:

```
foreach ($this->wave->getAllCustomers() as $customer) {
    echo $customer['name'];   // array access
    echo $customer->email;    // property access
}
```

### Available API Methods

[](#available-api-methods)

MethodDescription`getCustomers($vars)`Paginated customer list`getAllCustomers($vars)`All customers (handles pagination)`createCustomer($input)`Create a new customer`patchCustomer($input)`Update a customer (requires `id`)`deleteCustomer($customerId)`Delete a customer`getInvoices($vars)`Paginated invoice list`getAllInvoices($vars)`All invoices`createInvoice($input)`Create an invoice`approveInvoice($invoiceId)`Approve a draft invoice`sendInvoice($input)`Send an invoice by email`getAllProducts()`All products`getAllTaxes()`All sales taxes`getVendors($vars)`Paginated vendor list`getAllVendors()`All vendors`getAccounts($vars)`Paginated chart-of-accounts`getAllAccounts()`All chart-of-accounts entries`getAccount($accountId)`Single account`getAllBusinesses()`All businesses on the account`getBusiness($id)`Single business`getUser()`Authenticated user`rawQuery($query, $variables)`Execute a custom GraphQL query### Pagination

[](#pagination)

```
$wave->getCustomers(['page' => 1, 'pageSize' => 20]);

while ($wave->hasNextPage()) {
    $wave->nextPage();
    $wave->getCustomers();
}
```

---

Data Sync
---------

[](#data-sync)

Sync jobs persist Wave data to your local database. All jobs implement `ShouldQueue`.

### Full Sync

[](#full-sync)

Fetches all records from Wave and upserts them locally. After all pages are processed, any local record whose `wave_id` was **not** seen in Wave is deleted (orphan cleanup).

```
use Jeffgreco13\Wave\Jobs\SyncCustomersFromWave;

// Queue
SyncCustomersFromWave::dispatch();

// Or via Artisan
php artisan wave:sync-customers
```

### Incremental Sync

[](#incremental-sync)

Only fetches records modified after a given date. **Never deletes** local records — a missing record just means it was not recently modified, not that it was deleted.

```
// Sync records modified in the last 24 hours
SyncCustomersFromWave::dispatch(since: now()->subDay());
```

```
# Specific date
php artisan wave:sync-customers --since="2024-06-01"

# Automatically use the most recently synced local record's wave_modified_at
php artisan wave:sync-customers --since=last
```

### Sync All Entities

[](#sync-all-entities)

```
# Queue all sync jobs
php artisan wave:sync-all

# Run synchronously
php artisan wave:sync-all --sync

# With business override
php artisan wave:sync-all --business-id=QnVzaW5lc3M6...
```

### Querying Local Wave Models

[](#querying-local-wave-models)

```
use Jeffgreco13\Wave\Models\WaveCustomer;
use Jeffgreco13\Wave\Models\WaveInvoice;

// Active customers
WaveCustomer::active()->get();

// Find by Wave ID
WaveCustomer::where('wave_id', $id)->first();

// Unpaid invoices for a customer
WaveInvoice::active()->forCustomer($waveCustomerId)->status('UNPAID')->get();
```

---

Customer CRUD via Jobs
----------------------

[](#customer-crud-via-jobs)

```
use Jeffgreco13\Wave\Jobs\CreateWaveCustomer;
use Jeffgreco13\Wave\Jobs\UpdateWaveCustomer;
use Jeffgreco13\Wave\Jobs\DeleteWaveCustomer;

// Create in Wave and upsert locally
CreateWaveCustomer::dispatch([
    'name'  => 'Acme Corp',
    'email' => 'billing@acme.com',
]);

// Update (must include 'id' — Wave's customer UUID)
UpdateWaveCustomer::dispatch([
    'id'    => 'QnVzdG9tZXI6...',
    'email' => 'new@acme.com',
]);

// Delete from Wave and remove the local record
DeleteWaveCustomer::dispatch('QnVzdG9tZXI6...');
```

---

Custom Models
-------------

[](#custom-models)

To use your own Eloquent model, implement the `HasWaveSync` trait and register it in `config/wave.php`.

```
// app/Models/Customer.php
use Jeffgreco13\Wave\Traits\HasWaveSync;

class Customer extends Model
{
    use HasWaveSync;

    protected $fillable = ['wave_id', 'company_name', 'email', 'currency_code'];

    /**
     * Map local column names to Wave API field paths.
     * Use dot-notation for nested Wave objects.
     */
    public function waveAttributeMap(): array
    {
        return [
            'wave_id'       => 'id',
            'company_name'  => 'name',
            'email'         => 'email',
            'currency_code' => 'currency.code',
        ];
    }
}
```

Register in `config/wave.php`:

```
'models' => [
    'customer' => \App\Models\Customer::class,
],
```

All sync jobs (`SyncCustomersFromWave`, `CreateWaveCustomer`, etc.) will use your model automatically.

---

Available Artisan Commands
--------------------------

[](#available-artisan-commands)

CommandDescription`wave:sync-customers`Sync customers from Wave`wave:sync-all`Sync all entities`wave:pull-currencies`Cache Wave currency list locally**Options for `wave:sync-customers` and `wave:sync-all`:**

OptionDescription`--since="YYYY-MM-DD"`Incremental sync from a date`--since=last`Incremental from most recent local record`--business-id=`Override the configured business ID`--sync`Run synchronously (skip queue)`--fresh`Truncate the local table first (full sync only)---

Available Sync Jobs
-------------------

[](#available-sync-jobs)

JobSupports `$since`?Deletes orphans?`SyncCustomersFromWave`YesFull sync only`SyncInvoicesFromWave`YesFull sync only`SyncProductsFromWave`NoAlways (full sync)`SyncSalesTaxesFromWave`NoAlways`SyncVendorsFromWave`NoAlways`SyncBusinessesFromWave`NoAlways`SyncAccountsFromWave`NoAlways---

Data Enums
----------

[](#data-enums)

Use built-in enums for sort/filter values:

```
use Jeffgreco13\Wave\Data\CustomerSort;
use Jeffgreco13\Wave\Data\InvoiceSort;
use Jeffgreco13\Wave\Data\InvoiceStatus;
use Jeffgreco13\Wave\Data\InvoiceCreateStatus;
use Jeffgreco13\Wave\Data\ProductSort;

$wave->getCustomers(['sort' => CustomerSort::NAME_ASC]);
$wave->getInvoices(['status' => InvoiceStatus::UNPAID]);
```

---

Laravel Boost
-------------

[](#laravel-boost)

This package includes AI guidelines and a developer skill for [Laravel Boost](https://laravel.com/docs/13.x/boost). After installing Boost in your app, run:

```
php artisan boost:install
# or
php artisan boost:update --discover
```

Boost will automatically load the `wave-development` guidelines and skill to help AI agents write correct Wave integration code.

---

Changelog / Upgrade Guide
-------------------------

[](#changelog--upgrade-guide)

### v2.0

[](#v20)

- **Breaking:** Config key changed from `laravel-wave` to `wave`. Update any manual `config('laravel-wave.*')` calls to `config('wave.*')`.
- Added local Eloquent model sync (`wave_customers`, `wave_invoices`, `wave_products`, `wave_sales_taxes`, `wave_vendors`, `wave_businesses`, `wave_accounts`)
- Added `HasWaveSync` trait for custom model mapping
- Added sync jobs for all entities with full/incremental modes and orphan deletion
- Added `wave:sync-customers`, `wave:sync-all` Artisan commands
- Added `ManagesVendors` and `ManagesAccounts` traits to `WaveService`
- Added `deleteCustomer()` to `ManagesCustomers`
- Laravel Boost integration (`resources/boost/guidelines/` and `resources/boost/skills/`)

---

License
-------

[](#license)

MIT

###  Health Score

48

—

FairBetter than 94% of packages

Maintenance86

Actively maintained with recent releases

Popularity15

Limited adoption so far

Community14

Small or concentrated contributor base

Maturity65

Established project with proven stability

 Bus Factor2

2 contributors hold 50%+ of commits

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

Recently: every ~7 days

Total

16

Last Release

70d ago

Major Versions

v0.4.0 → v1.0.02025-11-27

v1.2.1 → 2.x-dev2026-06-01

### Community

Maintainers

![](https://www.gravatar.com/avatar/89c96adbc3b802ff12fb5ccfab0e0d6e352039505e9ee0cd13496c205a1d933e?d=identicon)[jeffgreco13](/maintainers/jeffgreco13)

---

Top Contributors

[![subbe](https://avatars.githubusercontent.com/u/3587988?v=4)](https://github.com/subbe "subbe (22 commits)")[![murraycollingwood](https://avatars.githubusercontent.com/u/5810216?v=4)](https://github.com/murraycollingwood "murraycollingwood (19 commits)")[![jeffgreco13](https://avatars.githubusercontent.com/u/12453974?v=4)](https://github.com/jeffgreco13 "jeffgreco13 (15 commits)")[![claude](https://avatars.githubusercontent.com/u/81847?v=4)](https://github.com/claude "claude (2 commits)")[![mrpangak](https://avatars.githubusercontent.com/u/44047484?v=4)](https://github.com/mrpangak "mrpangak (1 commits)")[![nhantrandev96](https://avatars.githubusercontent.com/u/43448496?v=4)](https://github.com/nhantrandev96 "nhantrandev96 (1 commits)")

###  Code Quality

TestsPHPUnit

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/jeffgreco13-laravel-wave/health.svg)

```
[![Health](https://phpackages.com/badges/jeffgreco13-laravel-wave/health.svg)](https://phpackages.com/packages/jeffgreco13-laravel-wave)
```

###  Alternatives

[statamic/cms

The Statamic CMS Core Package

4.9k3.8M1.1k](/packages/statamic-cms)[backpack/crud

Quickly build admin interfaces using Laravel, Bootstrap and JavaScript.

3.4k3.8M227](/packages/backpack-crud)[unopim/unopim

UnoPim Laravel PIM

10.8k2.5k](/packages/unopim-unopim)[leantime/leantime

Open source project management system for non-project managers. Simple like Trello, powerful like Jira. Built with neurodiversity in mind.

11.3k4.0k](/packages/leantime-leantime)[tencentcloud/tencentcloud-sdk-php

TencentCloudApi php sdk

3661.3M49](/packages/tencentcloud-tencentcloud-sdk-php)[eslazarev/wildberries-sdk

Wildberries OpenAPI clients (generated).

353.6k](/packages/eslazarev-wildberries-sdk)

PHPackages © 2026

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