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

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

sonnenglas/takealot-php-sdk
===========================

Framework-agnostic PHP SDK for the Takealot Marketplace API (sales, offers, transactions, balances, returns, shipments) with continuation-token pagination and 429 retry handling.

v1.0.1(1mo ago)07MITPHPPHP &gt;=8.2CI passing

Since Jun 23Pushed 1mo agoCompare

[ Source](https://github.com/sonnenglas/takealot-php-sdk)[ Packagist](https://packagist.org/packages/sonnenglas/takealot-php-sdk)[ Docs](https://github.com/sonnenglas/takealot-php-sdk)[ RSS](/packages/sonnenglas-takealot-php-sdk/feed)WikiDiscussions master Synced 2w ago

READMEChangelogDependencies (9)Versions (3)Used By (0)

takealot-php-sdk
================

[](#takealot-php-sdk)

Framework-agnostic PHP SDK for the [Takealot Marketplace API](https://marketplace-api.takealot.com/v1/docs) — read seller sales, offers, transactions, balances, returns, shipments, facilities, and account information from your Takealot Seller account.

[![Packagist Version](https://camo.githubusercontent.com/aece4da42034a76061b8e1e7df691f74d79b441d79f496c3abd988e3f0f46ace/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f736f6e6e656e676c61732f74616b65616c6f742d7068702d73646b2e737667)](https://packagist.org/packages/sonnenglas/takealot-php-sdk)[![Packagist Downloads](https://camo.githubusercontent.com/6e830ec6686723127d268795c5e8cc40272375a6782d7ce57f7e52c1b3b62770/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f736f6e6e656e676c61732f74616b65616c6f742d7068702d73646b2e737667)](https://packagist.org/packages/sonnenglas/takealot-php-sdk)[![PHP Version](https://camo.githubusercontent.com/d379f58a292b682b8d049cd53e5ac84e7ac693adfd702e34d219c6679e2ab359/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f736f6e6e656e676c61732f74616b65616c6f742d7068702d73646b2e737667)](https://packagist.org/packages/sonnenglas/takealot-php-sdk)[![License](https://camo.githubusercontent.com/7013272bd27ece47364536a221edb554cd69683b68a46fc0ee96881174c4214c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75652e737667)](LICENSE)[![PHPStan](https://camo.githubusercontent.com/1bc07920f0d36e55c17e1d38b1caa132cc605f51a82b388c962870b9a747b898/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048505374616e2d6c6576656c253230392d627269676874677265656e2e737667)](phpstan.neon)

---

Features
--------

[](#features)

- **Framework-agnostic.** Plain PSR-18 (HTTP client), PSR-17 (factories), and PSR-7 (messages). No Laravel, no Symfony, no global state — drop it into any modern PHP project.
- **Read-only and safe.** The SDK wraps the Marketplace API's `GET` endpoints only. It never creates, updates, or disables anything on your account — so there is no risk of an accidental price change or a disabled offer.
- **Type-safe DTOs.** Readonly response objects with strict shape validation. Malformed upstream payloads fail loudly instead of leaking untyped arrays through your code.
- **Continuation-token pagination, two ways.** Fetch a single `Page` and follow the token yourself, or `iterate()` a lazy `Generator` that walks every page transparently.
- **Automatic rate-limit handling.** HTTP 429 responses are retried automatically, honouring the `Retry-After` header, with exponential backoff as a fallback. Configurable via `maxRetries`.
- **Typed exception hierarchy.** `400`, `401/403`, `404`, and `429` each map to a distinct exception subclass — no need to `grep` on status codes.
- **Hardened by default.** 8 MiB response body cap, JSON depth limit of 64, and PSR-18 transport-error wrapping that scrubs the `X-API-Key` header from leaked messages.
- **PHPStan level 9.** Strict types throughout, zero static-analysis errors.

Why this SDK?
-------------

[](#why-this-sdk)

Takealot does not publish an official PHP SDK at the time of writing. This package is built against the current public [Takealot Marketplace API](https://marketplace-api.takealot.com/v1/docs) at `https://marketplace-api.takealot.com/v1`, targets modern PHP (8.2+), and stays out of your dependency-injection container by design.

It is the integration layer SONNENGLAS uses to pull our South African marketplace sales and settlement data into our own systems.

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

[](#requirements)

- **PHP** 8.2 or newer.
- A **PSR-18** HTTP client. [Guzzle 7](https://docs.guzzlephp.org/) is the recommended default and is automatically discovered via [`php-http/discovery`](https://docs.php-http.org/en/latest/discovery.html).

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

[](#installation)

```
composer require sonnenglas/takealot-php-sdk
```

If you do not already have a PSR-18 client installed:

```
composer require guzzlehttp/guzzle
```

`php-http/discovery` auto-wires any installed PSR-18 client and PSR-17 factories — you only need to inject them manually if you want to override defaults (timeouts, retry middleware, a mock client in tests, etc.).

Quick start
-----------

[](#quick-start)

### 1. Construct the client

[](#1-construct-the-client)

Generate an API key in the Takealot Seller Portal under **Settings → API Access**, then construct the client with it. Everything else is optional.

```
use Sonnenglas\Takealot\Client;

$client = new Client(apiKey: getenv('TAKEALOT_API_KEY'));
```

The key is sent as the `X-API-Key` header on every request. Only one API key can be active per seller account at a time.

### 2. List a page of sales

[](#2-list-a-page-of-sales)

```
$page = $client->sales()->list([
    'order_date__gte' => '2026-06-01',   // inclusive, YYYY-MM-DD, SAST
    'order_date__lte' => '2026-06-30',
    'limit'           => 100,            // 1–100, default 20
    'include_count'   => true,
]);

foreach ($page->items as $sale) {
    printf(
        "Order %d · %s · R%d · %s\n",
        $sale->orderId,
        $sale->sku,
        $sale->sellingPrice,
        $sale->salesRegion ?? 'unknown',
    );
}

echo "Matching sales: " . ($page->count ?? 'n/a') . "\n";
echo $page->hasMore() ? "More pages available.\n" : "Last page.\n";
```

### 3. Iterate every sale across pages

[](#3-iterate-every-sale-across-pages)

`iterate()` follows the `continuation_token` for you, so you never have to manage paging by hand:

```
$totalUnits = 0;

foreach ($client->sales()->iterate(['order_date__gte' => '2026-06-01']) as $sale) {
    $totalUnits += $sale->quantity;
}

echo "Units sold in June: {$totalUnits}\n";
```

### 4. Read your account balance

[](#4-read-your-account-balance)

```
$balances = $client->balances()->get()->balances;   // nested ?Balances breakdown

printf(
    "Available for payout: R%.2f (held back R%.2f)\n",
    $balances?->available ?? 0.0,
    $balances?->heldBack ?? 0.0,
);
```

Documentation
-------------

[](#documentation)

- [Documentation home](docs/README.md)
- **Guides**
    - [Installation](docs/guides/installation.md)
    - [Quickstart](docs/guides/quickstart.md)
    - [Pagination](docs/guides/pagination.md)
    - [Error handling](docs/guides/error-handling.md)
    - [Rate limiting &amp; retries](docs/guides/rate-limiting.md)
    - [Laravel integration](docs/guides/laravel-integration.md)
- **API reference**
    - [Overview](docs/api/README.md)
    - [`Client`](docs/api/client.md)
    - [Resources](docs/api/resources.md)
    - [DTOs](docs/api/dtos.md)
    - [Enums](docs/api/enums.md)
    - [Exceptions](docs/api/exceptions.md)
- **Runnable examples** — see [`examples/`](examples/)

Supported endpoints
-------------------

[](#supported-endpoints)

The SDK targets the seller-facing **read** surface of the Marketplace API. Every collection endpoint supports continuation-token pagination, `fields`selection, and (where applicable) `expands`.

ResourceEndpoint(s)AccessorOperationsSales`GET /sales``$client->sales()``list()`, `iterate()`Offers`GET /offers`, `GET /offers/{id}`, `GET /offers/by_sku/{sku}`, `GET /offers/by_barcode/{barcode}``$client->offers()``list()`, `iterate()`, `getById()`, `getBySku()`, `getByBarcode()`Transactions`GET /transactions``$client->transactions()``list()`, `iterate()`Balances`GET /balances``$client->balances()``get()`Returns`GET /returns`, `GET /returns/{id}``$client->returns()``list()`, `iterate()`, `getById()`Shipments`GET /shipments`, `GET /shipments/{id}``$client->shipments()``list()`, `iterate()`, `getById()`Facilities`GET /facilities/get_enabled_regions``$client->facilities()``enabledRegions()`Seller`GET /seller``$client->seller()``get()`Single-item lookups (`getById()`, `getBySku()`, `getByBarcode()`, `returns()->getById()`, `shipments()->getById()`) return the DTO, or `null` when the item does not exist (HTTP 404) — they do not throw on a missing item.

> **Write operations are out of scope.** The Marketplace API exposes offer-management endpoints (`POST /offers`, `PATCH /offers/{id}`, `POST /offers/batch`). This SDK deliberately does **not** wrap them — it is a read-only client. Call them directly if you need to mutate offers.

Pagination
----------

[](#pagination)

Collection endpoints return a [`Page`](docs/api/resources.md#pagination):

```
$page = $client->sales()->list(['limit' => 50]);

$page->items;             // list
$page->continuationToken; // string|null — the token for the next page
$page->count;             // int|null — total matches (only with include_count=true)
$page->hasMore();         // bool — true when continuationToken !== null
```

To walk every page manually, feed the token back in. **When a continuation token is supplied, all other query parameters are ignored by the API** — pass the token alone:

```
$params = ['order_date__gte' => '2026-06-01', 'limit' => 100];

do {
    $page = $client->sales()->list($params);

    foreach ($page->items as $sale) {
        // ...
    }

    $params = ['continuation_token' => $page->continuationToken];
} while ($page->hasMore());
```

Or let the SDK do it for you with `iterate()` — see the [pagination guide](docs/guides/pagination.md).

Rate limiting &amp; retries
---------------------------

[](#rate-limiting--retries)

The client retries HTTP 429 responses automatically:

- It reads the `Retry-After` header (integer seconds or an HTTP-date) and waits that long before retrying, capped at 60 seconds per attempt.
- If no usable `Retry-After` is present, it falls back to exponential backoff (1s, 2s, 4s, …, capped at 60s).
- After `maxRetries` (default `3`) exhausted attempts, it throws `RateLimitException`, which exposes `$retryAfter` for your own scheduling.

Tune or disable retries via the constructor:

```
// More patient: up to 5 retries.
$client = new Client(apiKey: $key, maxRetries: 5);

// Fail fast: no automatic retries.
$client = new Client(apiKey: $key, maxRetries: 0);
```

See the [rate-limiting guide](docs/guides/rate-limiting.md) for details and for how to inject a no-op sleeper in tests.

Error handling
--------------

[](#error-handling)

All SDK exceptions extend `Sonnenglas\Takealot\Exceptions\TakealotException`.

HTTPExceptionWhen400`ValidationException`Invalid query parameters or filters.401 / 403`AuthenticationException`Missing, invalid, or deactivated API key.404`NotFoundException`A missing resource. Single-item lookups catch this and return `null` instead.429`RateLimitException` (`$retryAfter`)Rate limit hit after automatic retries were exhausted.other`ApiException`Any other 4xx/5xx, oversized body, or malformed JSON.—`TransportException`The PSR-18 client failed (DNS / TCP / TLS / timeout). `statusCode` is `0`.`ApiException` (and therefore every subclass) carries `$statusCode` and the decoded `$responseBody`:

```
use Sonnenglas\Takealot\Exceptions\AuthenticationException;
use Sonnenglas\Takealot\Exceptions\RateLimitException;
use Sonnenglas\Takealot\Exceptions\TakealotException;

try {
    $page = $client->sales()->list(['order_date__gte' => '2026-06-01']);
} catch (AuthenticationException $e) {
    // Check that TAKEALOT_API_KEY is set and still active in the Seller Portal.
    throw $e;
} catch (RateLimitException $e) {
    sleep($e->retryAfter ?? 5);
    // ...retry...
} catch (TakealotException $e) {
    error_log("Takealot API error ({$e->getCode()}): {$e->getMessage()}");
    throw $e;
}
```

See the [error-handling guide](docs/guides/error-handling.md) for the full decision matrix.

Testing
-------

[](#testing)

The SDK is built test-first against `php-http/mock-client`, so you can exercise every code path without touching the live API. Swap in a mock PSR-18 client and a no-op `Sleeper` to make retry tests instant:

```
use GuzzleHttp\Psr7\HttpFactory;
use GuzzleHttp\Psr7\Response;
use Http\Mock\Client as MockClient;
use Sonnenglas\Takealot\Client;

$mock = new MockClient();
$mock->addResponse(new Response(200, [], json_encode([
    'items' => [/* ...sale rows... */],
    'limit' => 20,
], JSON_THROW_ON_ERROR)));

$factory = new HttpFactory();
$client = new Client(
    apiKey: 'key_test',
    httpClient: $mock,
    requestFactory: $factory,
);

$page = $client->sales()->list(['limit' => 20]);
```

Run the SDK's own suite with:

```
composer test       # PHPUnit
composer phpstan    # PHPStan level 9
composer check      # phpstan + test together
```

Versioning
----------

[](#versioning)

This project follows [Semantic Versioning 2.0.0](https://semver.org/spec/v2.0.0.html). See [CHANGELOG.md](CHANGELOG.md) for the release history.

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

[](#contributing)

Pull requests, issues, and discussions are welcome. Please read [CONTRIBUTING.md](CONTRIBUTING.md) before opening a PR — it covers the dev setup, coding standards, and the test-first workflow used throughout the codebase.

Security vulnerabilities should be reported privately — see [SECURITY.md](SECURITY.md).

License
-------

[](#license)

Released under the [MIT License](LICENSE).

Credits
-------

[](#credits)

Built and maintained by [Przemek Peron](mailto:przemek@sonnenglas.net).

If this SDK saves you time, please consider starring the [GitHub repository](https://github.com/sonnenglas/takealot-php-sdk).

###  Health Score

39

—

LowBetter than 84% of packages

Maintenance90

Actively maintained with recent releases

Popularity6

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

2

Last Release

45d ago

### Community

Maintainers

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

---

Top Contributors

[![przemekperon](https://avatars.githubusercontent.com/u/169778?v=4)](https://github.com/przemekperon "przemekperon (5 commits)")

---

Tags

sdkpsr-18ecommercemarketplaceSouth Africatakealot

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/sonnenglas-takealot-php-sdk/health.svg)

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

###  Alternatives

[telnyx/telnyx-php

Official Telnyx PHP SDK — APIs for Voice, SMS, MMS, WhatsApp, Fax, SIP Trunking, Wireless IoT, Call Control, and more. Build global communications on Telnyx's private carrier-grade network.

36826.2k2](/packages/telnyx-telnyx-php)[flow-php/flow

PHP ETL - Extract Transform Load - Data processing framework

86337.5k](/packages/flow-php-flow)[tempest/framework

The PHP framework that gets out of your way.

2.3k37.6k19](/packages/tempest-framework)[getbrevo/brevo-php

Official PHP SDK for the Brevo API.

1004.1M58](/packages/getbrevo-brevo-php)[gotenberg/gotenberg-php

A PHP client for interacting with Gotenberg, a developer-friendly API for converting numerous document formats into PDF files, and more!

3906.6M32](/packages/gotenberg-gotenberg-php)[laudis/neo4j-php-client

Neo4j-PHP-Client is the most advanced PHP Client for Neo4j

187738.3k47](/packages/laudis-neo4j-php-client)

PHPackages © 2026

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