PHPackages                             ucubix/php-client - 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. ucubix/php-client

ActiveLibrary[API Development](/categories/api)

ucubix/php-client
=================

UCubix Distribution API PHP Client with built-in rate limiting and DTO support

v1.0.0(1mo ago)010↑500%MITPHPPHP ^8.2

Since Apr 9Pushed 1mo agoCompare

[ Source](https://github.com/a2zwebltd/ucubix-php-client)[ Packagist](https://packagist.org/packages/ucubix/php-client)[ RSS](/packages/ucubix-php-client/feed)WikiDiscussions master Synced 1mo ago

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

UCubix PHP Client
=================

[](#ucubix-php-client)

PHP client for the [UCubix Distribution API](https://ucubix.com) with built-in rate limiting, typed DTOs, and full endpoint coverage.

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

[](#requirements)

- PHP 8.2+
- Guzzle 7.8+

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

[](#installation)

```
composer require ucubix/php-client
```

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

[](#quick-start)

```
use Ucubix\PhpClient\Client\UcubixClient;

$client = new UcubixClient(apiKey: 'YOUR_API_KEY');

// Find a product
$products = $client->getProducts(['search' => 'Cyberpunk']);
$product = $client->getProduct($products->data[0]->id);

// Check regional pricing
foreach ($product->regional_pricing as $region) {
    echo "{$region->region_code} ({$region->reseller_wsp}% WSP)\n";
    foreach ($region->countries as $country) {
        echo "  {$country->country_name}: {$country->price} {$country->currency_code}\n";
    }
}

// Create an order
$order = $client->createOrder(
    productUuid: $product->id,
    quantity: 1,
    regionCode: $product->regional_pricing[0]->region_code,
    countryCode: $product->regional_pricing[0]->countries[0]->country_code,
);

echo "Order {$order->id} — status: {$order->status}\n";

// Get license keys when order is fulfilled
$items = $client->getOrderItems($order->id);
foreach ($items->data as $item) {
    if ($item->hasLicenseKey()) {
        $key = $client->getLicenseKey($item->license_key_uuid);
        echo "Key: {$key->license_key}\n";
    }
}
```

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

[](#configuration)

```
$client = new UcubixClient(
    apiKey: 'YOUR_API_KEY',
    baseUrl: 'https://ucubix.com/api/v1/',  // default
);
```

---

API Methods
-----------

[](#api-methods)

### Organisation Info

[](#organisation-info)

MethodReturns`getOrganisation()`[`Organisation`](#organisation)```
$org = $client->getOrganisation();
echo $org->summary->total_usd_equivalent;
```

### Products

[](#products)

MethodReturns`getProducts(filters, page, perPage, sort)`[`PaginatedResponse`](#paginatedresponse)```getProduct(id)`[`Product`](#product)`getProductPhotos(id, page, perPage)`[`PaginatedResponse`](#paginatedresponse)```getProductScreenshots(id, page, perPage)`[`PaginatedResponse`](#paginatedresponse)```getProductCategories(id, page, perPage)`[`PaginatedResponse`](#paginatedresponse)```getProductPublishers(id, page, perPage)`[`PaginatedResponse`](#paginatedresponse)```getProductPlatforms(id, page, perPage)`[`PaginatedResponse`](#paginatedresponse)```getProductFranchises(id, page, perPage)`[`PaginatedResponse`](#paginatedresponse)```getProductDevelopers(id, page, perPage)`[`PaginatedResponse`](#paginatedresponse)``**`getProducts()` filters** (validated, throws `InvalidArgumentException` on unknown keys):

KeyTypeDescription`search``string`Full-text search`category``string`Category UUID`publisher``string`Publisher UUID`developer``string`Developer UUID`franchise``string`Franchise UUID`platform``string`Platform UUID**Sort options:** `name`, `-name`, `created_at`, `-created_at`

```
$products = $client->getProducts(
    filters: ['search' => 'Game', 'platform' => 'platform-uuid'],
    page: 1,
    perPage: 15,
    sort: 'name',
);

$product = $client->getProduct('product-uuid');
$photos  = $client->getProductPhotos('product-uuid');
```

### Orders

[](#orders)

MethodReturns`getOrders(filters, page, perPage, sort)`[`PaginatedResponse`](#paginatedresponse)```getOrder(id)`[`Order`](#order)`getOrderItems(orderId, page, perPage)`[`PaginatedResponse`](#paginatedresponse)```createOrder(productUuid, quantity, regionCode, countryCode?)`[`Order`](#order)`updateOrder(id, quantity)`[`Order`](#order)`cancelOrder(id)``bool`**`getOrders()` filters** (validated, throws `InvalidArgumentException` on unknown keys):

KeyTypeDescription`code``string`Filter by order code`external_reference``string`Filter by external reference**Sort options** (default: `-order_date`): `code`, `status`, `total_price`, `srp`, `currency_code`, `order_date`, `approved_at`, `rejected_at`, `delivered_at`, `distribution_model`

```
$orders = $client->getOrders(filters: ['code' => 'ORD-001'], sort: '-order_date');
$order  = $client->getOrder('order-uuid');
$items  = $client->getOrderItems('order-uuid');

$order = $client->createOrder('product-uuid', 5, 'NorthAmerica', 'us');
$order = $client->updateOrder('order-uuid', quantity: 10);
$client->cancelOrder('order-uuid');
```

### License Keys

[](#license-keys)

MethodReturns`getLicenseKey(id)`[`LicenseKey`](#licensekey)`getBulkLicenseKeys(ids)`[`LicenseKey[]`](#licensekey)```
$key  = $client->getLicenseKey('license-key-uuid');
$keys = $client->getBulkLicenseKeys(['uuid-1', 'uuid-2']); // up to 1000
```

### Catalog Dictionaries

[](#catalog-dictionaries)

MethodReturns`getCategories(page, perPage, sort)`[`PaginatedResponse`](#paginatedresponse)```getPublishers(page, perPage, sort)`[`PaginatedResponse`](#paginatedresponse)```getPlatforms(page, perPage, sort)`[`PaginatedResponse`](#paginatedresponse)```getDevelopers(page, perPage, sort)`[`PaginatedResponse`](#paginatedresponse)```getFranchises(page, perPage, sort)`[`PaginatedResponse`](#paginatedresponse)`````
$categories = $client->getCategories(sort: 'name');
$publishers = $client->getPublishers();
$platforms  = $client->getPlatforms();
$developers = $client->getDevelopers();
$franchises = $client->getFranchises();
```

---

Pagination
----------

[](#pagination)

All list endpoints return [`PaginatedResponse`](#paginatedresponse)``:

```
$page = 1;
do {
    $orders = $client->getOrders(page: $page, perPage: 50);

    foreach ($orders->data as $order) {
        // process order
    }

    $page++;
} while ($orders->hasMorePages());
```

---

DTOs
----

[](#dtos)

All DTOs extend `Spatie\LaravelData\Data`. Properties are `readonly`.

### Product

[](#product)

PropertyTypeNotes`id``string`UUID`name``string``summary``?string``description``?string``release_date``?string`ISO 8601`type``?string`e.g. "Game"`created_at``?string`ISO 8601`regional_pricing`[`RegionalPricing[]`](#regionalpricing)Only on single-resource requests`metadata`[`?ProductMetadata`](#productmetadata)System requirements, SteamDB### RegionalPricing

[](#regionalpricing)

PropertyType`region_code``string``reseller_wsp``float``countries`[`CountryPrice[]`](#countryprice)### CountryPrice

[](#countryprice)

PropertyType`country_name``string``country_code``string``price``?float``currency_code``?string``is_promotion``bool``original_price``?float``promotion_name``?string``promotion_end_date``?string``can_be_ordered``bool``in_stock``bool`### ProductMetadata

[](#productmetadata)

PropertyType`minimum`[`SystemRequirement[]`](#systemrequirement)`recommended`[`SystemRequirement[]`](#systemrequirement)`steamdb`[`?SteamdbInfo`](#steamdbinfo)### SystemRequirement

[](#systemrequirement)

PropertyType`parameter``?string``value``?string`### SteamdbInfo

[](#steamdbinfo)

PropertyType`id``int``type``string``url``string`### Order

[](#order)

PropertyTypeNotes`id``string`UUID`code``string``external_reference``?string``external_reference_attempt``?int``status``string`See [`OrderStatus`](#orderstatus)`total_price``float``srp``float``estimated_cost``?float``items_count``int``currency_code``?string`ISO 4217`order_date``string`ISO 8601`approved_at``?string``rejected_at``?string``delivered_at``?string``distribution_model``?string`"sale", "consignment"`rejection_note``?string`Helper: `$order->getStatus()` returns [`OrderStatus`](#orderstatus) enum.

### OrderItem

[](#orderitem)

PropertyTypeNotes`id``string`UUID`price``float``country_code``?string`ISO 3166-1 alpha-2`license_key_uuid``?string`Only when order is fulfilled/delivered`fulfilled_at``?string``created_at``?string``updated_at``?string`Helper: `$item->hasLicenseKey()` returns `bool`.

### LicenseKey

[](#licensekey)

PropertyType`id``string``license_key``string``created_at``?string``updated_at``?string`### Organisation

[](#organisation)

PropertyType`uuid``string``name``string``summary`[`OrganisationSummary`](#organisationsummary)`credit_lines`[`CreditLine[]`](#creditline)### OrganisationSummary

[](#organisationsummary)

PropertyType`currencies``int``total_usd_equivalent``string`### CreditLine

[](#creditline)

PropertyType`currency``string``balance``string`### Category

[](#category)

PropertyType`id``string``name``string``parent_id``?string``child_ids``string[]`### Publisher / Developer

[](#publisher--developer)

PropertyType`id``string``name``string``website``?string``about``?string``created_at``?string``updated_at``?string`### Platform

[](#platform)

PropertyType`id``string``name``string``created_at``?string``updated_at``?string`### Franchise

[](#franchise)

PropertyType`id``string``name``string``created_at``?string`### Media

[](#media)

PropertyType`id``string``name``string``file_name``string``collection_name``string``mime_type``string``disk``string``size``int``order_column``?int``url``string``created_at``?string``updated_at``?string`### PaginatedResponse

[](#paginatedresponse)

PropertyType`data``T[]``currentPage``int``perPage``int``total``int``lastPage``int``firstPageUrl``?string``lastPageUrl``?string``nextPageUrl``?string``prevPageUrl``?string`Helper: `$response->hasMorePages()` returns `bool`.

---

Enums
-----

[](#enums)

### OrderStatus

[](#orderstatus)

```
use Ucubix\PhpClient\Enums\OrderStatus;

OrderStatus::NEW;        // 'new'
OrderStatus::PENDING;    // 'pending'
OrderStatus::APPROVED;   // 'approved'
OrderStatus::REJECTED;   // 'rejected'
OrderStatus::FULFILLED;  // 'fulfilled'
OrderStatus::DELIVERED;  // 'delivered'
OrderStatus::CANCELLED;  // 'cancelled'
```

---

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

[](#error-handling)

All API errors throw typed exceptions:

```
use Ucubix\PhpClient\Exceptions\ApiException;
use Ucubix\PhpClient\Exceptions\AuthenticationException;
use Ucubix\PhpClient\Exceptions\RateLimitException;
use Ucubix\PhpClient\Exceptions\ValidationException;

try {
    $order = $client->createOrder($uuid, 5, 'InvalidRegion');
} catch (AuthenticationException $e) {
    // 401 Unauthorized or 403 Forbidden
    // Invalid API key or IP not whitelisted
    echo $e->getMessage();
    echo $e->getCode(); // 401 or 403

} catch (ValidationException $e) {
    // 422 Unprocessable Entity
    echo $e->getMessage(); // e.g. "Quantity must not be greater than 1."
    echo $e->field;        // field name if provided

} catch (RateLimitException $e) {
    // 429 Too Many Requests (after all retries exhausted)
    echo $e->retryAfter;   // seconds to wait

} catch (ApiException $e) {
    // All other errors (400, 404, 500, etc.)
    echo $e->getMessage();
    echo $e->getCode();
    echo $e->errorKey;
    echo $e->errorDetail;
}
```

### Exception Hierarchy

[](#exception-hierarchy)

```
ApiException
  ├── AuthenticationException  (401, 403)
  ├── RateLimitException       (429)
  └── ValidationException      (422)

```

---

Rate Limiting
-------------

[](#rate-limiting)

The client has a dual-layer rate limiting system, matching the [SharpAPI php-core](https://github.com/sharpapi/php-core) pattern.

### 1. Client-side Sliding Window

[](#1-client-side-sliding-window)

Proactive throttling: the client tracks request timestamps in a sliding window and blocks (via `usleep` + 50ms buffer) before exceeding the configured requests per minute. This prevents hitting the server limit.

```
// Check/configure requests per minute (default: 100)
$client->getRequestsPerMinute();   // 100
$client->setRequestsPerMinute(50); // slow down
$client->setRequestsPerMinute(0);  // disable client-side throttling

// Direct access to the rate limiter
$limiter = $client->getRateLimiter();
$limiter->canProceed();  // non-blocking check
$limiter->remaining();   // slots left in current window
```

### 2. Server-side 429 Retry

[](#2-server-side-429-retry)

Reactive handling: if the server returns `429 Too Many Requests`, the client automatically retries up to 3 times, respecting the `Retry-After` header.

```
// Configure max retries (default: 3)
$client->setMaxRetryOnRateLimit(5);
```

### 3. Server Header Tracking

[](#3-server-header-tracking)

After every response, the client reads `X-RateLimit-Limit` and `X-RateLimit-Remaining` headers.

```
$client->getRateLimitLimit();     // e.g. 100
$client->getRateLimitRemaining(); // e.g. 87
$client->canMakeRequest();        // true if remaining > 0
```

### 4. Server-side Limit Adaptation

[](#4-server-side-limit-adaptation)

If the server reports a higher limit via `X-RateLimit-Limit` header, the client automatically adapts its sliding window upward (one-way ratchet — never decreases).

### 5. State Persistence

[](#5-state-persistence)

Export/restore rate limit state for caching across requests:

```
// Export
$state = $client->getRateLimitState();
// ['limit' => 100, 'remaining' => 87]

// Restore (e.g. from Redis/session)
$client->setRateLimitState($state);
```

### API Rate Limits

[](#api-rate-limits)

- **100 requests per minute** per API key

---

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

[](#authentication)

The API uses Bearer Token authentication with IP whitelisting:

```
Authorization: Bearer YOUR_API_KEY
Accept: application/vnd.api+json
Content-Type: application/json

```

Requests from non-whitelisted IPs receive a `403 Forbidden` error.

---

Testing
-------

[](#testing)

```
composer install
vendor/bin/phpunit
```

License
-------

[](#license)

MIT. See [LICENSE](LICENSE).

###  Health Score

40

—

FairBetter than 88% of packages

Maintenance94

Actively maintained with recent releases

Popularity7

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity46

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

Unknown

Total

1

Last Release

31d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/9d92cd9be3f984a45cbdba6721edf633e02a6e3ec16b684cb857f173db1c5f89?d=identicon)[PavelDenisovDev](/maintainers/PavelDenisovDev)

---

Top Contributors

[![PavelDenisovDev](https://avatars.githubusercontent.com/u/110802437?v=4)](https://github.com/PavelDenisovDev "PavelDenisovDev (1 commits)")

---

Tags

apiclientlicensedistributiondigitalucubix

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/ucubix-php-client/health.svg)

```
[![Health](https://phpackages.com/badges/ucubix-php-client/health.svg)](https://phpackages.com/packages/ucubix-php-client)
```

###  Alternatives

[openai-php/laravel

OpenAI PHP for Laravel is a supercharged PHP API client that allows you to interact with the Open AI API

3.7k7.6M74](/packages/openai-php-laravel)[resend/resend-php

Resend PHP library.

564.7M21](/packages/resend-resend-php)[crowdin/crowdin-api-client

PHP client library for Crowdin API v2

611.5M5](/packages/crowdin-crowdin-api-client)[mozex/anthropic-laravel

Anthropic PHP for Laravel is a supercharged PHP API client that allows you to interact with the Anthropic API

71226.4k1](/packages/mozex-anthropic-laravel)[markrogoyski/numverify-api-client-php

Numverify API Client for PHP

1220.9k](/packages/markrogoyski-numverify-api-client-php)[azuracast/php-api-client

An API client library for the AzuraCast API

311.3k](/packages/azuracast-php-api-client)

PHPackages © 2026

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