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

075PHP

Since Jun 1Pushed 1mo 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 today

READMEChangelogDependenciesVersions (1)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 the "Leverkusen" warehouse and get its net stock
$warehouses   = $connector->stock()->warehouses()->json();
$leverkusenId = null;
foreach ($warehouses as $wh) {
    if (stripos($wh['name'], 'Leverkusen') !== false) {
        $leverkusenId = $wh['id'];
        break;
    }
}
foreach ($entries as $e) {
    if ($e['warehouseId'] === $leverkusenId) {
        echo "Leverkusen netto: {$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";
}
```

### Properties

[](#properties)

MethodDescriptionAPI Endpoint`properties()->list(?int $page, ?int $itemsPerPage, ?string $with)`List all properties (paginated)`GET /rest/properties``properties()->groups(?int $page, ?int $itemsPerPage, ?string $with)`List all property groups (paginated)`GET /rest/properties/groups````
$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');
```

### 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

23

—

LowBetter than 26% of packages

Maintenance61

Regular maintenance activity

Popularity12

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity11

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.

### 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 (16 commits)")

---

Tags

e-commercephpplentymarketsplentyonerest-apisaloon-phpsdk

### 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

[exsyst/swagger

A php library to manipulate Swagger specifications

35916.4M7](/packages/exsyst-swagger)[hubspot/api-client

Hubspot API client

24016.2M20](/packages/hubspot-api-client)[pocketmine/bedrock-protocol

An implementation of the Minecraft: Bedrock Edition protocol in PHP

172445.0k15](/packages/pocketmine-bedrock-protocol)[botman/driver-telegram

Telegram driver for BotMan

93459.5k6](/packages/botman-driver-telegram)

PHPackages © 2026

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