PHPackages                             codebes/gripp-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. [HTTP &amp; Networking](/categories/http)
4. /
5. codebes/gripp-sdk

ActiveLibrary[HTTP &amp; Networking](/categories/http)

codebes/gripp-sdk
=================

PHP SDK for the Gripp CRM/ERP API. Fluent query builder, batch operations, and 54 resources for project management, invoicing, time tracking, and more.

v1.2.1(2mo ago)06MITPHPPHP ^8.1CI passing

Since Feb 27Pushed 2mo agoCompare

[ Source](https://github.com/Codebes-NL/gripp-sdk)[ Packagist](https://packagist.org/packages/codebes/gripp-sdk)[ RSS](/packages/codebes-gripp-sdk/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (6)Dependencies (5)Versions (7)Used By (0)

Gripp SDK for PHP
=================

[](#gripp-sdk-for-php)

[![Latest Version on Packagist](https://camo.githubusercontent.com/a1e9fa3b40c913b0cc30108a46f37c4dbe07533168cb28c26c88f69b67cb4727/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f636f64656265732f67726970702d73646b2e737667)](https://packagist.org/packages/codebes/gripp-sdk)[![Tests](https://github.com/Codebes-NL/gripp-sdk/actions/workflows/tests.yml/badge.svg)](https://github.com/Codebes-NL/gripp-sdk/actions/workflows/tests.yml)[![PHPStan](https://github.com/Codebes-NL/gripp-sdk/actions/workflows/static-analysis.yml/badge.svg)](https://github.com/Codebes-NL/gripp-sdk/actions/workflows/static-analysis.yml)[![License: MIT](https://camo.githubusercontent.com/784362b26e4b3546254f1893e778ba64616e362bd6ac791991d2c9e880a3a64e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d677265656e2e737667)](LICENSE)[![PHP Version](https://camo.githubusercontent.com/d08f28d855a66e7623b92f4a52e88d351accab94ffa88f40dee0a784bff91734/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f636f64656265732f67726970702d73646b2e737667)](https://packagist.org/packages/codebes/gripp-sdk)

A PHP SDK for the [Gripp](https://www.gripp.com) (now [Exact Gripp](https://www.exact.com/nl/producten/exact-gripp)) CRM/ERP API. Manage companies, contacts, projects, invoices, time tracking, and 50+ other resources through a fluent query builder with batch operations, auto-pagination, and automatic retries. Works with any PHP 8.1+ application, including Laravel.

Features
--------

[](#features)

- Fluent query builder with 14 filter operators
- Full CRUD support on 54 Gripp resources
- Batch operations (multiple API calls in a single HTTP request)
- Auto-pagination for large datasets
- Automatic retries on server errors and connection failures
- Typed exceptions for authentication, rate limiting, and API errors
- Laravel Collection responses out of the box
- Self-documenting resources with field types, required fields, and relationship metadata

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

[](#requirements)

- PHP 8.1+
- A Gripp API token and API URL

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

[](#installation)

```
composer require codebes/gripp-sdk
```

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

[](#configuration)

### Option 1: Environment variables

[](#option-1-environment-variables)

Set `GRIPP_API_TOKEN` in your `.env` file or environment:

```
GRIPP_API_TOKEN=your-api-token
```

Then call configure without arguments:

```
use CodeBes\GrippSdk\GrippClient;

GrippClient::configure();
```

The SDK uses `https://api.gripp.com` by default. To override, set `GRIPP_API_URL` in your environment.

### Option 2: Explicit configuration

[](#option-2-explicit-configuration)

```
use CodeBes\GrippSdk\GrippClient;

GrippClient::configure(token: 'your-api-token');
```

### Option 3: Interactive setup

[](#option-3-interactive-setup)

```
vendor/bin/gripp-setup
```

This creates a `.env` file with your credentials.

Quick Start
-----------

[](#quick-start)

```
use CodeBes\GrippSdk\GrippClient;
use CodeBes\GrippSdk\Resources\Company;
use CodeBes\GrippSdk\Resources\Contact;
use CodeBes\GrippSdk\Resources\Project;

// Configure once at application boot
GrippClient::configure();

// Find a record by ID
$company = Company::find(123);

// Get all records (auto-paginated)
$allCompanies = Company::all();

// Query with filters
$activeCompanies = Company::where('active', true)
    ->orderBy('companyname', 'asc')
    ->limit(50)
    ->get();

// Create a record
$result = Company::create([
    'companyname' => 'Acme Corp',
    'relationtype' => 'COMPANY',
    'email' => 'info@acme.com',
]);

// Update a record
Company::update(123, [
    'phone' => '+31 20 123 4567',
]);

// Delete a record
Company::delete(123);
```

Query Builder
-------------

[](#query-builder)

The query builder provides a fluent interface for filtering, ordering, and paginating results.

```
use CodeBes\GrippSdk\Resources\Project;

// Simple equality filter (two-argument form)
$projects = Project::where('company', 42)->get();

// With operator (three-argument form)
$projects = Project::where('name', 'contains', 'Website')->get();

// Chain multiple filters
$results = Project::where('company', 42)
    ->where('archived', false)
    ->orderBy('createdon', 'desc')
    ->limit(25)
    ->offset(0)
    ->get();

// Get just the first match
$project = Project::where('name', 'contains', 'Redesign')->first();

// Count matching records
$count = Project::where('archived', false)->count();
```

### Supported Filter Operators

[](#supported-filter-operators)

OperatorDescription`equals`Exact match (default when using two-argument `where`)`notequals`Not equal to`contains`String contains`notcontains`String does not contain`startswith`String starts with`endswith`String ends with`greaterthan`Greater than`lessthan`Less than`greaterequals`Greater than or equal to`lessequals`Less than or equal to`in`Value is in array`notin`Value is not in array`isnull`Field is null (pass `true` as value)`isnotnull`Field is not null (pass `true` as value)### Date Helpers

[](#date-helpers)

Common date filtering patterns are built into the query builder:

```
use CodeBes\GrippSdk\Resources\Project;
use CodeBes\GrippSdk\Resources\Hour;

// Filter by year
$projects = Project::where('archived', false)
    ->whereYear('createdon', 2026)
    ->get();

// Filter by month
$hours = Hour::where('employee', 42)
    ->whereMonth('date', 2026, 3)
    ->get();

// Filter by date range
$invoices = Invoice::where('company', 10)
    ->whereDateBetween('date', '2026-01-01', '2026-03-31')
    ->get();

// Modified since (for incremental syncing)
$updated = Project::where('archived', false)
    ->whereModifiedSince(new DateTime('2026-03-01 00:00:00'))
    ->get();
```

### Auto-Prefixing

[](#auto-prefixing)

Field names are automatically prefixed with the entity name when using the query builder. Writing `Project::where('createdon', ...)` produces the filter field `project.createdon`. Fully qualified fields like `project.createdon` are left as-is.

### Auto-Pagination

[](#auto-pagination)

Both `get()` and the query builder's `get()` automatically paginate through all results. Use `limit()` when you only want a specific number of results (single API call):

```
// Fetches ALL matching projects across all pages
$all = Project::where('archived', false)->get();

// Fetches only the first 25 (single page)
$page = Project::where('archived', false)->limit(25)->get();
```

Batch Operations
----------------

[](#batch-operations)

Group multiple API calls into a single HTTP request for better performance:

```
use CodeBes\GrippSdk\GrippClient;
use CodeBes\GrippSdk\Resources\Company;
use CodeBes\GrippSdk\Resources\Contact;

$transport = GrippClient::getTransport();
$transport->startBatch();

// Queue multiple calls (these don't execute yet)
Company::find(1);
Company::find(2);
Contact::find(10);

// Execute all queued calls in a single HTTP request
$responses = $transport->executeBatch();

foreach ($responses as $response) {
    $rows = $response->rows();
    // Process each response...
}
```

Rate Limit Awareness
--------------------

[](#rate-limit-awareness)

The transport tracks rate limit headers from API responses and provides hooks for proactive budget management:

```
$transport = GrippClient::getTransport();

// Check current rate limit state (from most recent response headers)
$transport->getRateLimitRemaining(); // e.g. 847
$transport->getRateLimitLimit();     // e.g. 1000

// Abort requests when budget is low
$transport->beforeRequest(function (int $requestCount, ?int $remaining, ?int $limit) {
    if ($remaining !== null && $remaining onRateLimitExceeded(function (?int $retryAfter, ?int $remaining) {
    // Set a flag, notify monitoring, etc.
    Log::warning("Gripp rate limit hit, retry after {$retryAfter}s");
});
```

The SDK treats both HTTP 429 and HTTP 503 with Gripp error code 1004 (short-burst throttle) as rate limit errors.

Error Handling
--------------

[](#error-handling)

The SDK throws specific exceptions for different error types:

```
use CodeBes\GrippSdk\Exceptions\AuthenticationException;
use CodeBes\GrippSdk\Exceptions\RateLimitException;
use CodeBes\GrippSdk\Exceptions\RequestException;
use CodeBes\GrippSdk\Exceptions\GrippException;

try {
    $company = Company::find(123);
} catch (AuthenticationException $e) {
    // 401 or 403 - invalid token or forbidden
    if ($e->isTokenInvalid()) {
        // Handle invalid/expired token
    }
    if ($e->isForbidden()) {
        // Handle insufficient permissions
    }
} catch (RateLimitException $e) {
    // 429 - too many requests
    $retryAfter = $e->getRetryAfter(); // seconds to wait
    $remaining = $e->getRemaining();   // remaining requests
} catch (RequestException $e) {
    // Other API errors
    $data = $e->getResponseData(); // raw error response
} catch (GrippException $e) {
    // Base exception for all SDK errors (e.g. not configured)
}
```

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

[](#available-resources)

All resources support **read** operations. Resources that also support create, update, and/or delete are indicated below.

ResourceCreateReadUpdateDelete`AbsenceRequest`xxxx`AbsenceRequestLine`xxxx`BulkPrice`xxxx`CalendarItem`xxxx`Company`xxxx`CompanyDossier`xxxx`Contact`xxxx`Contract`xxxx`ContractLine`xxxx`Cost`x`CostHeading`xxxx`Department`xxxx`Employee`xxxx`EmployeeFamily`xxxx`EmployeeTarget`x`EmployeeYearlyLeaveBudget`xxx`EmploymentContract`xxxx`ExternalLink`xxxx`File`x`Hour`xxxx`Invoice`xxxx`InvoiceLine`xxxx`Ledger`xxxx`Memorial`x`MemorialLine`x`Notification``Offer`xxxx`OfferPhase`xxxx`OfferProjectLine`xxxx`Packet`xxxx`PacketLine`xxxx`Payment`xxxx`PriceException`xxxx`Product`xxxx`Project`xxxx`ProjectPhase`xxxx`PurchaseInvoice`xxxx`PurchaseInvoiceLine`xxxx`PurchaseOrder`xxxx`PurchaseOrderLine`xxxx`PurchasePayment`xxxx`RejectionReason`xxxx`RevenueTarget`x`Tag`xxxx`Task`xxxx`TaskPhase`xxxx`TaskType`xxxx`TimelineEntry`xxxx`UmbrellaProject`xxx`Unit`xxxx`Webhook`xxxx`YearTarget`x`YearTargetType`x**Special resources:**

- `Notification` has custom `emit()` and `emitall()` methods instead of CRUD.
- `Company` has additional `getCompanyByCOC()`, `addInteractionByCompanyId()`, and `addInteractionByCompanyCOC()` methods.

Resource Metadata
-----------------

[](#resource-metadata)

Every resource class exposes constants that describe its schema:

```
use CodeBes\GrippSdk\Resources\Company;

Company::FIELDS;    // ['id' => 'int', 'companyname' => 'string', ...]
Company::READONLY;  // ['createdon', 'updatedon', 'id', 'searchname', 'files']
Company::REQUIRED;  // ['relationtype']
Company::RELATIONS; // ['accountmanager' => Employee::class, 'tags' => Tag::class, ...]
```

- `FIELDS` maps field names to their types (`string`, `int`, `float`, `boolean`, `datetime`, `date`, `array`, `customfields`, `color`)
- `READONLY` lists fields that cannot be written to
- `REQUIRED` lists fields that must be provided when creating/updating
- `RELATIONS` maps foreign key fields to their related resource classes

Auto-Pagination
---------------

[](#auto-pagination-1)

Both `all()` and `get()` automatically handle pagination, fetching all matching records transparently:

```
// Fetches all companies, regardless of how many pages it takes
$companies = Company::all(); // Returns Illuminate\Support\Collection

// Filtered queries also auto-paginate
$active = Company::where('active', true)->get(); // All pages
```

Response Format
---------------

[](#response-format)

All collection methods return `Illuminate\Support\Collection` instances. Single-record methods return associative arrays or `null`.

```
$companies = Company::where('active', true)->get();

// Use Collection methods
$names = $companies->pluck('companyname');
$grouped = $companies->groupBy('visitingaddress_city');
$first = $companies->first();
```

Testing
-------

[](#testing)

```
composer test
```

Or directly:

```
vendor/bin/phpunit
```

Changelog
---------

[](#changelog)

Please see the [GitHub Releases](https://github.com/Codebes-NL/gripp-sdk/releases) page for more information on what has changed recently.

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

[](#contributing)

Contributions are welcome! Please open a pull request against the `main` branch. All PRs require:

- Passing tests (`composer test`)
- Code style compliance (`composer cs`)
- Static analysis passing (`composer analyse`)
- Code owner approval

License
-------

[](#license)

MIT - see [LICENSE](LICENSE) for details.

###  Health Score

38

—

LowBetter than 85% of packages

Maintenance85

Actively maintained with recent releases

Popularity5

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity47

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

6

Last Release

77d ago

### Community

Maintainers

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

---

Top Contributors

[![Brentjes](https://avatars.githubusercontent.com/u/1493297?v=4)](https://github.com/Brentjes "Brentjes (12 commits)")

---

Tags

apicomposer-packagecrmerpexactexact-grippexact-onlinegrippinvoicingjson-rpclaravelphpproject-managementsdktime-trackingphpapilaravelsdkGuzzlecrmjson-rpcinvoicingtime trackingERPproject managementexactExact OnlineGrippexact-gripp

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/codebes-gripp-sdk/health.svg)

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

###  Alternatives

[ory/hydra-client-php

Documentation for all of Ory Hydra's APIs.

1710.8k](/packages/ory-hydra-client-php)

PHPackages © 2026

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