firebearstudio/client-prestashop-api
A PHP client for the PrestaShop API, providing a simple, object-oriented way to query and manage products, orders, customers, categories, and other shop resources. Supports CRUD operations, filtering, and integration into Laravel/PHP applications.
1. Install and confirm what you actually got. The package is a thin API client, not a Laravel package with a full abstraction layer, so inspect it before wiring it in:
composer require firebearstudio/client-prestashop-api
Then look at, in order:
composer.json — namespace, PHP version constraint, whether it declares a Laravel service provider under extra.laravel.providers, and whether it uses Guzzle or Laravel’s HTTP client.src/ — the client entrypoint and how resources/methods are exposed (typically get, create, update, delete per PrestaShop resource).README.md and any tests/ — the only reliable documentation for method signatures.config/ — whether a config file is publishable.If there is no auto-discovered provider, register the client manually:
// app/Providers/AppServiceProvider.php
public function register(): void
{
$this->app->singleton(PrestashopClient::class, function () {
return new PrestashopClient(
baseUrl: config('services.prestashop.url'),
apiKey: config('services.prestashop.key'),
);
});
}
Adjust the class name/constructor to the package’s actual signature.
2. Prepare PrestaShop first. In the PrestaShop back office:
GET, POST, PUT, DELETE) for only the resources you need.curl -u "YOUR_API_KEY:" "https://shop.example.com/api/products?limit=0,1&display=full"
A 401 here is almost always key permissions, URL rewriting, or a missing trailing slash — fix that before debugging the package.
3. Configure Laravel. Keep credentials out of code:
// config/services.php
'prestashop' => [
'url' => env('PRESTASHOP_URL'), // https://shop.example.com/api
'key' => env('PRESTASHOP_API_KEY'),
'timeout' => env('PRESTASHOP_TIMEOUT', 30),
],
4. First use case: pull a product into Laravel. The first useful task is almost always a read-only sync to prove connectivity and understand the payload shape:
$client = app(PrestashopClient::class);
// List endpoints return IDs only by default — always ask for full data.
$products = $client->get('products', [
'display' => 'full',
'limit' => '0,50',
'sort' => '[id_ASC]',
]);
Persist the raw response once, inspect the XML/JSON structure, then map it into a local model. Do not start with product creation — PrestaShop’s write payloads are much less forgiving than reads.
Wrap the package behind your own service. Given the package’s low adoption (0 stars, 0 dependents), treat it as an implementation detail. Define an interface such as PrestashopGateway and bind the package client to it. If the package stalls or you need to swap to direct HTTP calls, only one class changes.
interface PrestashopGateway
{
public function findProductByReference(string $reference): ?array;
public function upsertProduct(array $data): int;
}
Read sync: IDs first, then hydrate in chunks. PrestaShop list endpoints are cheap when returning IDs and expensive with display=full. A reliable pattern:
limit=0,100, then limit=100,100, until fewer than the page size come back.filter[id]=[1|2|3|...] with display=full.id, and store date_upd so later runs can skip unchanged records.Write sync: build payloads from schema=blank. The single most useful PrestaShop API feature for a developer is the schema endpoint:
// Returns an empty resource with every writable field.
$blank = $client->get('products', ['schema' => 'blank']);
// Returns field descriptions and types.
$synopsis = $client->get('products', ['schema' => 'synopsis']);
Use schema=blank as the canonical template for create and update payloads. Do not hand-craft minimal payloads and hope — PrestaShop’s update semantics are closer to replace than patch.
Product creation is a multi-step workflow, not one call. A realistic product sync:
POST /products — create the product shell.PUT /stock_availables/{id} — stock is a separate resource keyed by product/combination.POST /images/products/{productId} — multipart image upload.Wrap this in a database transaction locally and a queued job remotely. If step 3 fails, your local record should still know the product ID exists.
Use jobs and rate limiting for anything bulk. PrestaShop’s webservice is not designed for high concurrency and will slow down under parallel writes. Dispatch chunked jobs with RateLimited middleware or Bus::batch(), and make each job idempotent by checking your local mapping table before writing.
Keep an ID mapping table. Never assume SKU/reference is unique in PrestaShop — it is not enforced by default. Maintain:
Schema::create('prestashop_mappings', function (Blueprint $table) {
$table->id();
$table->string('resource'); // products, orders, customers
$table->string('local_id');
$table->unsignedBigInteger('remote_id');
$table->timestamp('remote_updated_at')->nullable();
$table->unique(['resource', 'local_id']);
});
Order sync via polling, not webhooks. PrestaShop has no native webhooks. Poll with date filters:
$orders = $client->get('orders', [
'display' => 'full',
'date' => '1',
'filter[date_upd]' => '[' . $lastSync->format('Y-m-d H:i:s') . ',]',
'limit' => '0,100',
]);
Store the max date_upd seen and use it as the next lower bound. For order status changes, read order_histories rather than mutating the order directly.
Testing. If the package uses Guzzle, inject a MockHandler; if it uses Laravel’s HTTP client, Http::fake() works. Keep fixture XML/JSON files from real responses — they are your contract tests and catch PrestaShop version differences.
GET /api/products without display=full gives you a list of <product id="1" xlink:href="..."/> elements. This is the most common first-hour confusion.schema=blank, populate, then send the full resource.limit=start,count, not page numbers. There is usually no total count in the response. Loop until a page returns fewer rows than requested.filter[reference]=[SKU1|SKU2], ranges are [min,max], and values need URL encoding. Test filters with curl before encoding them in PHP.401 vs 404 vs 500. 401 means bad key or missing resource permission. 404 often means the resource ID does not exist or the URL is malformed. 500 frequently contains a useful XML error body — log the raw response, not just the status code.output_format=JSON on reads and the matching Content-Type on writes, and confirm the store’s PrestaShop version supports JSON input. XML remains the safest common denominator.<language id="1">...</language>). Sending a scalar will fail or silently write to the wrong language.PUTs, and use exponential backoff. Never blindly retry POSTs without an idempotency check.composer.json, read the source when behavior is unclear, and avoid relying on undocumented methods. The release date is unusual — verify the tag and changelog before upgrading in production.curl first, then compare the package’s generated request. Log the full URL, headers, and raw response body at debug level; PrestaShop’s error messages are often only in the body.How can I help you explore Laravel packages today?