PHPackages                             macropage/plentyone-php-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. macropage/plentyone-php-sdk

ActiveLibrary[API Development](/categories/api)

macropage/plentyone-php-sdk
===========================

PlentyOne REST API SDK based on Saloon PHP

v0.1.0(2w ago)0135MITPHPPHP ^8.2

Since Jul 30Pushed 1w agoCompare

[ Source](https://github.com/michabbb/plentyone-php-sdk)[ Packagist](https://packagist.org/packages/macropage/plentyone-php-sdk)[ RSS](/packages/macropage-plentyone-php-sdk/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (1)Dependencies (5)Versions (2)Used By (0)

PlentyOne PHP SDK
=================

[](#plentyone-php-sdk)

A lightweight PHP SDK for the [PlentyONE REST API](https://developers.plentymarkets.com), built on [Saloon PHP v4](https://docs.saloon.dev).

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

[](#requirements)

- PHP 8.2+
- Composer

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

[](#installation)

```
composer require macropage/plentyone-php-sdk
```

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

[](#quick-start)

```
use PlentyOne\PlentyOneConnector;

$connector = new PlentyOneConnector('https://your-instance.plentymarkets.com/rest');
$connector->login('username', 'password');

// Find a variation by SKU
$variation = $connector->variations()->find('YOUR-SKU')->json('entries.0');

// Find a variation by EAN/barcode
$variation = $connector->variations()->list(['barcode' => '4002516915737'])->json('entries.0');

// Get all images for an item
$images = $connector->images()->forItem($variation['itemId'])->json();
```

Authentication
--------------

[](#authentication)

The SDK handles Bearer token authentication automatically. After calling `login()`, the token is stored in memory and sent with every request. If the token expires (24h), the SDK re-authenticates automatically before the next request.

```
$connector = new PlentyOneConnector('https://your-instance.plentymarkets.com/rest');
$connector->login('username', 'password');

// All subsequent calls are authenticated
```

Supported API Calls
-------------------

[](#supported-api-calls)

The SDK exposes resources via the connector. Each resource returns a Saloon `Response` object that you can call `->json()` on (or `->json('path.to.value')` for dot-notation access).

### Items

[](#items)

MethodDescriptionAPI Endpoint`items()->get(int $itemId, ?string $with, ?string $lang)`Get a single item (incl. texts)`GET /rest/items/{id}``items()->list(...)`List items with filters`GET /rest/items`**Available filters for `list()`:** `id`, `name`, `manufacturerId`, `flagOne`, `flagTwo`, `page`, `itemsPerPage`, `with`, `lang`, `updatedBetween`, `variationUpdatedBetween`, `variationRelatedUpdatedBetween`, `or`

```
// Item with German texts
$item = $connector->items()->get(699331)->json();
$name = $item['texts'][0]['name1'] ?? null;

// Items by manufacturer
$items = $connector->items()->list(manufacturerId: '1', itemsPerPage: 50)->json();
```

### Variations

[](#variations)

MethodDescriptionAPI Endpoint`variations()->find(string $numberExact)`Find variation by SKU`GET /rest/items/variations?numberExact=...``variations()->get(int $itemId, int $variationId, ?string $with)`Get a specific variation`GET /rest/items/{id}/variations/{varId}``variations()->list(array $filters)`List variations with filters`GET /rest/items/variations``variations()->documents(int $itemId, int $variationId)`Get file-type properties (documents)`GET /rest/items/{id}/variations/{varId}``variations()->addDocument(int $itemId, int $variationId, int $propertyId, string $fileUrl)`Add or update a document`POST/PUT /rest/properties/relations``variations()->removeDocument(int $itemId, int $variationId, int $propertyId)`Remove a document`DELETE /rest/properties/relations/{id}`**Available filters for `list()`:** `numberExact`, `id`, `itemId`, `isActive`, `isMain`, `isBundle`, `page`, `itemsPerPage`, `categoryId`, `plentyId`, `referrerId`, `manufacturerId`, `supplierId`, `variationTagId`, `storeSpecial`, `with`, `lang`, `numberFuzzy`, `barcode`, `itemName`, `itemDescription`, `flagOne`, `flagTwo`, `sku`, `supplierNumber`, `supplierNumberFuzzy`, `updatedBetween`, `createdBetween`, `relatedUpdatedBetween`, `stockWarehouseId`

**Useful `with` relations:** `item`, `variationBarcodes`, `variationCategories`, `variationDefaultCategory`, `variationSalesPrices`, `variationSuppliers`, `variationShippingProfiles`, `variationClients`, `variationMarkets`, `tags`, `properties`, `variationProperties`

The default variation response already includes `purchasePrice` (current EK netto), `movingAveragePrice` (gleitender Durchschnitts-EK), `weightG`, `weightNetG`, `widthMM`, `lengthMM`, `heightMM` and many more fields without any `with` parameter.

### Images

[](#images)

MethodDescriptionAPI Endpoint`images()->forItem(int $itemId)`Get all images of an item`GET /rest/items/{id}/images``images()->forVariation(int $itemId, int $variationId)`Get variation image links`GET /rest/.../variation_images``images()->upload(...)`Upload an image (via URL or base64)`POST /rest/items/{id}/images/upload``images()->updatePosition(int $itemId, int $imageId, int $position)`Change image sort order`PUT /rest/items/{id}/images/{imgId}``images()->delete(int $itemId, int $imageId)`Delete an image`DELETE /rest/items/{id}/images/{imgId}``images()->linkToVariation(int $itemId, int $variationId, int $imageId)`Link image to a variation`POST /rest/.../variation_images``images()->unlinkFromVariation(int $itemId, int $variationId, int $imageId)`Unlink image from a variation`DELETE /rest/.../variation_images/{imgId}`#### Upload via URL

[](#upload-via-url)

```
$response = $connector->images()->upload(
    itemId: 668423,
    uploadUrl: 'https://example.com/image.png',
    position: 0,
    name: 'Product front',
    alternate: 'Alt text for SEO',
);
$imageId = $response->json('id');
```

#### Upload via base64

[](#upload-via-base64)

```
$base64 = base64_encode(file_get_contents('/path/to/image.png'));

$response = $connector->images()->upload(
    itemId: 668423,
    uploadImageData: $base64,
    uploadFileName: 'product.png',
    fileType: 'png',
    position: 0,
);
$imageId = $response->json('id');
```

> **Note:** PlentyONE processes images asynchronously. Right after upload, `width`, `height`, and `size` may still be `0`. The metadata is populated after a few seconds.

### Categories

[](#categories)

MethodDescriptionAPI Endpoint`categories()->list(array $filters)`List categories with filters`GET /rest/categories``categories()->get(int $id, ?string $with, ?string $lang, ...)`Get a single category by ID`GET /rest/categories/{id}`**Available filters for `list()`:** `type`, `with`, `page`, `itemsPerPage`, `parentId`, `lang`, `name`, `level`, `plentyId`, `linklist`, `updatedAt`, `tagId`, `metaKeywords`

```
// Single category with German details
$response = $connector->categories()->get(4737, with: 'details', lang: 'de');
$category = $response->json('entries.0');
echo $category['details'][0]['name']; // "Miele"
echo $category['parentCategoryId'];   // 1793
```

> **Note:** `categories()->get()` returns a paginated response with one entry — even for a single-ID lookup. Always grab `entries.0`.

### Manufacturers

[](#manufacturers)

MethodDescriptionAPI Endpoint`manufacturers()->get(int $id)`Get a single manufacturer by ID`GET /rest/items/manufacturers/{id}````
$itemId = 699331;
$item   = $connector->items()->get($itemId)->json();
$manu   = $connector->manufacturers()->get($item['manufacturerId'])->json();
echo $manu['name']; // "Miele"
```

### Accounts (Contacts / Suppliers)

[](#accounts-contacts--suppliers)

Suppliers in PlentyONE are stored as contacts with `typeId = 4`.

MethodDescriptionAPI Endpoint`accounts()->getContact(int $contactId, ?string $with)`Get a single contact (supplier, customer, …)`GET /rest/accounts/contacts/{id}````
// Resolve a supplier name from variationSuppliers
$variation = $connector->variations()->get($itemId, $varId, 'variationSuppliers')->json();
foreach ($variation['variationSuppliers'] as $sup) {
    $contact = $connector->accounts()->getContact($sup['supplierId'], 'options')->json();
    echo trim($contact['firstName'] . ' ' . $contact['lastName']) . "\n";
}
```

### Stock

[](#stock)

MethodDescriptionAPI Endpoint`stock()->list(?int $variationId, ?string $updatedAtFrom, ...)`List stock with filters`GET /rest/stockmanagement/stock``stock()->forVariation(int $variationId)`Convenience: stock entries for one variation`GET /rest/stockmanagement/stock?variationId=...``stock()->warehouses(?array $with)`List all warehouses (id, name, typeId, …). Pass `with: ['repairWarehouse']` to load the repair-warehouse relation.`GET /rest/stockmanagement/warehouses``stock()->redistribute(array $redistributions)`Rebook ("umbuchen") stock between warehouses / storage locations`PUT /rest/stockmanagement/stock/redistribute``stock()->moveBetweenWarehouses(int $variationId, int $currentWarehouseId, int $newWarehouseId, int $quantity, ...)`Convenience: move a single variation quantity between two warehouses`PUT /rest/stockmanagement/stock/redistribute````
// Net stock for one variation across all warehouses
$entries  = $connector->stock()->forVariation(35747)->json('entries');
$netTotal = array_sum(array_column($entries, 'netStock'));

// Find a warehouse by name and get its net stock
$warehouses  = $connector->stock()->warehouses()->json();
$warehouseId = null;
foreach ($warehouses as $wh) {
    if (stripos($wh['name'], 'Main Warehouse') !== false) {
        $warehouseId = $wh['id'];
        break;
    }
}
foreach ($entries as $e) {
    if ($e['warehouseId'] === $warehouseId) {
        echo "Net stock: {$e['netStock']}\n";
    }
}
```

#### Redistribute (rebook stock between warehouses)

[](#redistribute-rebook-stock-between-warehouses)

`redistribute()` moves stock from one warehouse/storage location to another – the total stock stays the same, only the location changes. For batch-managed or BBD/MHD variations, `batch` / `bestBeforeDate` must be included in the redistribution object.

```
// Move 2 units of a variation from warehouse 106 to warehouse 122
$connector->stock()->moveBetweenWarehouses(
    variationId: 3686,
    currentWarehouseId: 106,
    newWarehouseId: 122,
    quantity: 2,
    reasonId: 101, // movement reason (Bewegungsgrund), if required by your config
);

// Or several redistributions in one call
$connector->stock()->redistribute([
    ['variationId' => 3686, 'reasonId' => 101, 'quantity' => 2, 'currentWarehouseId' => 106, 'newWarehouseId' => 122],
    ['variationId' => 3686, 'reasonId' => 101, 'quantity' => 1, 'currentWarehouseId' => 125, 'newWarehouseId' => 122],
]);
```

> **Note:** This is a writing call. It actually moves stock in PlentyONE – test against a sandbox / with a safe `reasonId` before using it in production.

### Shipping

[](#shipping)

MethodDescriptionAPI Endpoint`shipping()->presets(...)`List shipping presets (profiles)`GET /rest/orders/shipping/presets``shipping()->forItem(int $itemId)`Item shipping profiles for one item`GET /rest/items/{id}/item_shipping_profiles``shipping()->allItemProfiles()`All item shipping profile links`GET /rest/items/item_shipping_profiles`### Webstores

[](#webstores)

MethodDescriptionAPI Endpoint`webstores()->list()`List all webstores/clients with PlentyID and name`GET /rest/webstores````
$webstores = $connector->webstores()->list()->json();
foreach ($webstores as $ws) {
    echo $ws['storeIdentifier'] . ': ' . $ws['name'] . "\n";
}
```

### Order Referrers (Sales Channels)

[](#order-referrers-sales-channels)

MethodDescriptionAPI Endpoint`referrers()->list()`List all order referrers/sales channels with ID and name`GET /rest/orders/referrers````
$referrers = $connector->referrers()->list()->json();
foreach ($referrers as $r) {
    echo $r['id'] . ': ' . ($r['backendName'] ?? $r['name']) . "\n";
}
```

### Orders

[](#orders)

MethodDescriptionAPI Endpoint`orders()->search(array $filters)`Search orders with filters (paginated)`GET /rest/orders/search``orders()->get(int $orderId, ?array $with)`Get a single order by ID`GET /rest/orders/{orderId}``orders()->statuses(?string $lang, ?int $page, ?int $itemsPerPage)`List the configured order statuses (id + names, paginated)`GET /rest/orders/statuses``orders()->update(int $orderId, array $body)`Update an order (send only changed fields)`PUT /rest/orders/{orderId}``orders()->setStatus(int $orderId, int|float|string $statusId)`Convenience: change an order's status`PUT /rest/orders/{orderId}`**Common filters for `search()`:** `orderId`, `plentyId`, `orderTypeId`, `statusId`, `referrerId`, `ownerId`, `locationId`, `createdAt`, `updatedAt`, `contactData`, `itemVariationId`, `variationNumber`, `documentNumber`, `tag`, `shippingStatus`, `sortBy`, `sortOrder`, `page`, `itemsPerPage`, `with`, `lazyLoaded`, `withDeleted`. Dynamic filters: `orderProperty_{typeId}`, `orderDate_{typeId}`, `documentNumber_{documentType}`, `addressRelation_{typeId}`, `relationReference_{referenceType}_{relationType}`.

**Order type IDs:** 1 = sales order, 2 = delivery, 3 = returns, 4 = credit note, 5 = warranty, 6 = repair, 7 = offer, 8 = advance order, 9 = multi-order, 10 = multi credit note, 11 = multi delivery, 12 = reorder, 13 = partial delivery.

> **Important:** The search loads **no relations by default** (`lazyLoaded = true`). To get `properties`, `orderItems`, `addresses` etc. you must request them via `with: [...]` (or set `lazyLoaded => false`).

```
// Find the Plenty order for an Amazon order number.
// The Amazon order id is stored as order property type 7 ("External order ID").
$resp = $connector->orders()->search([
    'orderProperty_7' => '123-1234567-1234567',
    'with'            => ['orderItems', 'addresses', 'properties'],
]);
$order = $resp->json('entries.0');

// Latest orders of a sales channel (referrerId 4.01 = Amazon Germany)
$latest = $connector->orders()->search([
    'referrerId'   => '4.01',
    'sortBy'       => 'orderId',
    'sortOrder'    => 'desc',
    'itemsPerPage' => 20,
    'with'         => ['properties'],
])->json('entries');

// Single order with relations
$order = $connector->orders()->get(12345, ['orderItems', 'addresses', 'relations'])->json();

// Configured order statuses (paginated). Statuses are NOT a fixed enum —
// they are configured per system, so resolve names from the instance.
$statuses = [];
$page = 1;
do {
    $resp = $connector->orders()->statuses('de', $page, 100);
    foreach ($resp->json('entries') as $s) {
        $statuses[(string) $s['statusId']] = $s['names']['de'] ?? null;
    }
    $isLast = $resp->json('isLastPage');
    $page++;
} while (! $isLast);
// $statuses now maps each configured statusId to its name, e.g. $statuses['7']

// Change an order's status (writing call — mutates the order in PlentyONE).
// Pass the exact configured statusId (sub-statuses are decimal, e.g. 8.01 !== 8.1).
$connector->orders()->setStatus(12345, 7);

// Or update several order fields at once.
$connector->orders()->update(12345, ['statusId' => 7]);
```

> **Note:** `update()` / `setStatus()` are **writing** calls that change real data in PlentyONE. Test against a non-critical order first. Order statuses are configured per system — resolve the target `statusId` via `orders()->statuses()`.

### Properties

[](#properties)

MethodDescriptionAPI Endpoint`properties()->list(?int $page, ?int $itemsPerPage, ?string $with)`List all properties (paginated)`GET /rest/properties``properties()->get(int $propertyId)`Get one property`GET /rest/properties/{propertyId}``properties()->create(array $payload)`Create a property (writing call)`POST /rest/properties``properties()->delete(int $propertyId)`Delete a property (writing call)`DELETE /rest/properties/{propertyId}``properties()->groups(?int $page, ?int $itemsPerPage, ?string $with)`List all property groups (paginated)`GET /rest/properties/groups``properties()->group(int $groupId, ?string $with)`Get one property group`GET /rest/properties/groups/{groupId}``properties()->attachToGroup(int $groupId, int $propertyId)`Attach a property to a group (writing call)`POST /rest/properties/groups/{groupId}/properties/{propertyId}``properties()->attachManyToGroups(array $relations)`Bulk-attach properties to groups (writing call)`PUT /rest/v2/properties/groups/relations````
$response   = $connector->properties()->list(page: 1, itemsPerPage: 100, with: 'names');
$properties = $response->json('entries');

$response = $connector->properties()->groups(page: 1, itemsPerPage: 100, with: 'names');
$groups   = $response->json('entries');

// Create a property. `position` is accepted by the API although it is absent
// from some endpoint descriptions.
$property = $connector->properties()->create([
    'names'          => [['lang' => 'en', 'name' => 'Range']],
    'typeIdentifier' => 'item',
    'cast'           => 'int',
    'position'       => 160,
]);

// Assign the new property to a group.
$connector->properties()->attachToGroup(42, $property->json('id'));

// Assign multiple existing properties to groups in one request.
$connector->properties()->attachManyToGroups([
    ['propertyId' => 123, 'groupId' => 42],
    ['propertyId' => 456, 'groupId' => 42],
]);
```

> **Note:** `create()`, `attachToGroup()` and `attachManyToGroups()` are **writing**calls that permanently change PlentyONE master data. Verify the payload in a dry run before applying it.

### Tags

[](#tags)

MethodDescriptionAPI Endpoint`tags()->list(?int $page, ?int $itemsPerPage, ?string $with)`List all tags`GET /rest/tags``tags()->link(int $tagId, string $tagType, int $relationshipValue)`Link a tag to a variation/item`POST /rest/tags/relationships``tags()->unlink(int $tagId, string $tagType, int $relationshipValue)`Unlink a tag from a variation/item`DELETE /rest/tags/relationships`### Catalogs

[](#catalogs)

MethodDescriptionAPI Endpoint`catalogs()->list()`List all catalogs`GET /rest/catalogs/catalogs``catalogs()->create(array $body)`Create a catalog`POST /rest/catalogs/catalogs``catalogs()->copy(array $body)`Copy one or more catalogs`PUT /rest/catalogs/catalogs/copy``catalogs()->copyFormat(string $catalogId, array $body)`Copy a catalog format`PUT /rest/catalogs/catalogs/{catalogId}/copy``catalogs()->import(array $body)`Import a catalog`POST /rest/catalogs/catalogs/import``catalogs()->migrate()`Migrate catalogs from Dynamo DB to S3`POST /rest/catalogs/catalogs/migrate``catalogs()->activate(string $id, bool $active = true)`Activate or deactivate a catalog`POST /rest/catalogs/catalogs/activate/{id}``catalogs()->archive()`List archived (deleted) catalogs`GET /rest/catalogs/catalogs/archive``catalogs()->restore(string $id)`Restore an archived catalog`POST /rest/catalogs/catalogs/archive/{id}/restore``catalogs()->get(string $id)`Get a single catalog`GET /rest/catalogs/catalogs/{id}``catalogs()->delete(string $id)`Delete a catalog`DELETE /rest/catalogs/catalogs/{id}``catalogs()->update(string $id, array $body)`Update a catalog`PUT /rest/catalogs/catalogs/{id}``catalogs()->content(string $id)`Get catalog content`GET /rest/catalogs/catalogs/{id}/content``catalogs()->updateContent(string $id, array $body)`Update catalog content`PUT /rest/catalogs/catalogs/{id}/content``catalogs()->preview(string $id)`Preview catalog data`GET /rest/catalogs/catalogs/{id}/preview``catalogs()->previewVdi(string $id, int $variationId)`Preview VDI catalog export`POST /rest/catalogs/catalogs/{id}/preview/vdi``catalogs()->publicUrl(string $id)`Get the public download URL`GET /rest/catalogs/catalogs/{id}/url/public``catalogs()->privateUrl(string $id)`Get the private download URL`GET /rest/catalogs/catalogs/{id}/url/private``catalogs()->export(string $id)`Get catalog export configuration`GET /rest/catalogs/catalogs/{id}/export``catalogs()->versions(string $id)`List all versions of a catalog`GET /rest/catalogs/catalogs/{id}/versions``catalogs()->version(string $id, string $versionId)`Get a specific catalog version`GET /rest/catalogs/catalogs/{id}/versions/{versionId}``catalogs()->templates()`List all catalog templates`GET /rest/catalogs/templates``catalogs()->scheduleDays()`List available schedule days`GET /rest/catalogs/catalogs/schedule/days``catalogs()->token()`Generate an alphanumeric token`GET /rest/catalogs/catalogs/token``catalogs()->checkConnection(string $protocol, array $body = [])`Check FTP/FTPS/SFTP connection`POST /rest/catalogs/connection/check/{protocol}`### Catalog Statuses

[](#catalog-statuses)

MethodDescriptionAPI Endpoint`catalogStatuses()->list(?string $catalogId, ?int $page, ?int $itemsPerPage)`List all catalog statuses (optional filter by catalogId)`GET /rest/catalogs/statuses``catalogStatuses()->get(int $id)`Get a specific catalog status`GET /rest/catalogs/statuses/{id}``catalogStatuses()->data(int $id)`Get status data`GET /rest/catalogs/statuses/{id}/data``catalogStatuses()->logs(int $id)`List status logs`GET /rest/catalogs/statuses/{id}/logs``catalogStatuses()->histories(int $id)`List status histories`GET /rest/catalogs/statuses/{id}/histories``catalogStatuses()->historyFile(int $id, string $filename)`Get a single status history file`GET /rest/catalogs/statuses/{id}/histories/{filename}``catalogStatuses()->cancel(int $statusId)`Cancel an export run`POST /rest/catalogs/statuses/{statusId}/cancel`### Documents (File-Properties)

[](#documents-file-properties)

Documents (manuals, data sheets, etc.) are stored as properties with `cast: "file"` on variations.

```
// Get all documents for a variation
$docs = $connector->variations()->documents($itemId, $variationId);

// Add a document (creates property link if it doesn't exist)
$connector->variations()->addDocument(
    itemId: 668423,
    variationId: 19408,
    propertyId: 498, // e.g. 498 = manual
    fileUrl: 'https://example.com/manual.pdf',
);

// Remove a document
$connector->variations()->removeDocument(
    itemId: 668423,
    variationId: 19408,
    propertyId: 498,
);
```

Need More?
----------

[](#need-more)

If you need additional endpoints, feel free to fork the repository or submit a pull request. The SDK follows a consistent Saloon pattern: one `Request` class per endpoint, grouped under a thin `Resource` class on the connector.

License
-------

[](#license)

MIT

###  Health Score

40

—

FairBetter than 86% of packages

Maintenance97

Actively maintained with recent releases

Popularity14

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity36

Early-stage or recently created project

 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

Unknown

Total

1

Last Release

19d ago

### Community

Maintainers

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

---

Top Contributors

[![michabbb](https://avatars.githubusercontent.com/u/3524595?v=4)](https://github.com/michabbb "michabbb (25 commits)")

---

Tags

e-commercephpplentymarketsplentyonerest-apisaloon-phpsdk

###  Code Quality

Static AnalysisPHPStan, Rector

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/macropage-plentyone-php-sdk/health.svg)

```
[![Health](https://phpackages.com/badges/macropage-plentyone-php-sdk/health.svg)](https://phpackages.com/packages/macropage-plentyone-php-sdk)
```

###  Alternatives

[saloonphp/laravel-plugin

The official Laravel plugin for Saloon

807.6M227](/packages/saloonphp-laravel-plugin)[myoutdeskllc/salesforce-php

salesforce library for php8+

1586.3k](/packages/myoutdeskllc-salesforce-php)[codebar-ag/laravel-docuware

DocuWare integration with Laravel

1125.1k](/packages/codebar-ag-laravel-docuware)[sandorian/moneybird-api-php

Moneybird API client for PHP

148.6k](/packages/sandorian-moneybird-api-php)[codebar-ag/laravel-zammad

Zammad integration with Laravel

107.4k](/packages/codebar-ag-laravel-zammad)[marceloeatworld/falai-php

\#1 PHP client for the fal.ai serverless AI platform, compatible with Laravel and native PHP, built on Saloon v4

106.2k](/packages/marceloeatworld-falai-php)

PHPackages © 2026

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