imper86/allegroapi
PHP SDK for the Allegro marketplace REST API. Typed request and response classes wrap authentication and API endpoints, letting PHP applications manage offers, orders, and account data without hand-rolling HTTP calls. Useful for adding Allegro listings and sales workflows to an existing backend.
The package is a PHP client wrapping Allegro's REST and legacy SOAP APIs, distributed via Composer:
composer require imper86/allegroapi
Before writing any code, register an application at https://apps.developer.allegro.pl/ and note:
https://api.allegro.pl) or sandbox (https://api.allegro.pl.allegrosandbox.pl)First look in these places:
Client / Credentials classes — this is the entry point that holds OAuth state.Service namespace (e.g. OrderService, OfferService, ProductService, ShippingService) — each service mirrors a slice of Allegro's API and is the surface you'll actually call day to day.AuthService — handles the OAuth2 authorization-code and refresh flows.A minimal first use case is listing the seller's orders:
$credentials = new Credentials($clientId, $clientSecret, $redirectUri);
$authService = new AuthService($credentials);
// 1. Redirect the user to $authService->getAuthorizationUrl()
// 2. Receive ?code=... on your redirect URI
$token = $authService->getAccessToken($code);
// 3. Build a client with the token
$client = new Client($credentials);
$client->setAccessToken($token);
$orders = (new OrderService($client))->getOrders([
'status' => 'READY_FOR_PROCESSING',
]);
That's the loop you'll be running most days: fetch a token, construct a service, call a method, read the response.
Centralize the client in the DI container. Never construct Client at the call site. Bind it as a singleton, hydrate it from stored credentials on boot, and inject the specific services where they're used. In Laravel, a small service provider reading tokens from the database or cache is enough; in Symfony, an autowired factory does the same job.
Persist the token, not the credentials. The library gives you a token object; serialize it and store it against the seller. Store access_token, refresh_token, and expires_at, then rehydrate on each request. expires_at should be treated as authoritative — Allegro invalidates tokens on its own schedule too, so a 401 is always possible even when the timestamp says you have time left.
Refresh lazily, once. Wrap all outgoing calls so that a 401 triggers a single refresh via AuthService::refreshToken() and one retry. Use a per-token lock (Redis SET NX or a database row lock) to prevent a fleet of concurrent workers stampeding the refresh endpoint, because Allegro will hand back different refresh tokens and you'll invalidate the others.
Treat services as thin repositories. Each *Service maps fairly directly onto a REST resource. Compose them into your own domain layer — e.g. a ListingImporter that pulls OfferService::getOffers() pages, maps to an internal DTO, and persists. Do not let controllers call Allegro services directly; response shapes vary in subtle ways between endpoints and you want one place to normalise them.
Paginate explicitly. Most list endpoints return { items: [...], totalCount, ... } and accept limit / offset query parameters. A typical loop:
$offset = 0;
do {
$page = $offerService->getOffers(['limit' => 100, 'offset' => $offset]);
foreach ($page->getItems() as $offer) { /* ... */ }
$offset += 100;
} while ($offset < $page->getTotalCount());
Sandbox first, always. Anything dealing with listings, orders, or payments should be exercised against the sandbox. The sandbox is a separate Allegro account with its own credentials, and data does not carry over. Wire the base URL through config rather than hardcoding.
Queue writes. POST/PUT/PATCH calls — creating offers, changing prices, updating stock — should go through a queue with retries and backoff. Allegro's write endpoints are the ones most likely to 429 or return transient 5xx.
Idempotency for writes. Allegro doesn't universally support idempotency keys, so before creating an offer or issuing a refund, check the current state. Prefer PATCH-style "set to desired state" calls over blind POST.
SOAP is legacy but still required for some operations. Certain order, commission, and payout endpoints only exist on the SOAP API (or the SOAP surface is the only documented one). The library exposes both, but they have different auth and error models — SOAP failures often come back as a generic fault with an unhelpful message. Wrap SOAP calls in a helper that inspects faultcode / faultstring explicitly rather than relying on the generic exception.
Locale and currency defaults bite. Prices and amounts are strings with fixed decimal precision; do not pass floats. Currency defaults to PLN, language defaults to pl-PL. If you're operating a cross-border setup, set both explicitly on every payload that accepts them.
Empty collections are the classic null-vs-array trap. Some endpoints return null for items when there are no results; others return []. Defensive mapping in your domain layer ($page->getItems() ?? []) prevents surprises, and don't rely on count() on a response object directly.
Rate limits are per-endpoint and undocumented in places. The library does not throttle for you. Expect 429s with Retry-After under any real load, and honour it. A simple token-bucket middleware in front of the client is the cheapest fix.
Token refresh race conditions are the number-one production bug with this package. Two workers call refreshToken() with the same refresh token; Allegro invalidates the first issue and returns a new refresh token; the loser writes its stale refresh token back and the seller is logged out the next time you try. Guard the refresh with a lock and only persist if the incoming refresh token matches what you currently store.
Version pinning matters. The package tracks Allegro's API changes but does not always follow semver perfectly. Pin to a known-good minor version in composer.json and read the changelog before bumping — service method signatures have changed between releases.
Error handling is not uniform. REST errors surface as exceptions with a Problem body (title, detail, status); SOAP errors do not. Build one exception wrapper that normalises both into something with code, message, and details you can log.
Extension points are limited but real. If you need a call the library doesn't expose, drop down to Client::get() / Client::post() with a raw path — the client handles auth and base URL, so you still get token management for free. This is the pragmatic path for niche endpoints rather than forking.
Log the request ID. Allegro returns X-Request-Id (or similar) on responses. Capture it in your HTTP middleware; when support asks what happened with a specific order, having that ID is the difference between a one-hour and one-day investigation.
Do not log token objects. They implement __toString/jsonSerialize and it's easy to accidentally dump them into logs, which is an incident waiting to happen.
Documentation is thin. The README covers authentication and a handful of services; for the rest, read the class methods and cross-reference with Allegro's official API docs. Budget a day to map the services you actually need.
How can I help you explore Laravel packages today?