TL;DRPrestaShop propose deux API pour lire et modifier une boutique depuis un autre logiciel : le Webservice, disponible sur toutes les versions depuis PrestaShop 1.5 et accessible à l'adresse /api/, et la nouvelle API Admin de PrestaShop 9, accessible à l'adresse /admin-api/. Ce guide montre comment activer chacune, s'authentifier proprement, filtrer, trier et paginer les résultats, puis les exploiter en PHP, avec des URL et du code prêts à copier.

Webservice ou API Admin : laquelle utiliser ?#
Les deux coexistent dans PrestaShop 9. Le Webservice reste le choix le plus simple et le plus documenté pour synchroniser un catalogue, des stocks ou des commandes ; l'API Admin est la base des futures intégrations, mais ses points d'accès s'étoffent encore de version en version.
| Webservice | API Admin (PrestaShop 9) | |
|---|---|---|
| Adresse | https://maboutique.com/api/ | https://maboutique.com/admin-api/ |
| Versions | PrestaShop 1.5 à 9 | PrestaShop 9 et suivantes |
| Formats | XML (par défaut) ou JSON | JSON |
| Accès | Clé de 32 caractères, droits par ressource | Client OAuth2, jeton à durée limitée, droits par scope |
| Où le configurer | Paramètres avancés > Webservice | Paramètres avancés > Admin API |
| Documentation interactive | Schémas via ?schema=blank | /admin-api/docs.html |
| Idéal pour | Synchronisations ERP, CRM, comparateurs, scripts existants | Nouvelles intégrations sur PrestaShop 9 |
Activer le Webservice et créer une clé#
- Dans le back-office, ouvrez Paramètres avancés > Webservice et passez « Activer le service web de PrestaShop » sur Oui.
- Cliquez sur Ajouter une nouvelle clé de service web, générez la clé (32 caractères) et donnez-lui une description qui dit à quoi elle sert (« ERP – lecture commandes », par exemple).
- Cochez uniquement les droits nécessaires, ressource par ressource : GET pour lire, POST pour créer, PUT pour modifier, DELETE pour supprimer.
- Enregistrez. En multiboutique, choisissez aussi les boutiques auxquelles la clé donne accès.
Bon à savoir : créez une clé par outil connecté, avec le minimum de droits. Si un prestataire n'a plus besoin d'accès, il suffit de désactiver sa clé, sans toucher aux autres intégrations.
S'authentifier : la clé dans l'en-tête, pas dans l'URL#
La documentation officielle recommande de transmettre la clé dans l'en-tête Authorization, en authentification HTTP Basic : la clé sert d'identifiant et le mot de passe reste vide. En PHP avec cURL, cela tient en deux options :
curl_setopt($ch, CURLOPT_USERPWD, $apiKey . ':'); // clé + mot de passe vide curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
Le Webservice accepte aussi la clé dans l'URL (?ws_key=VOTRE_CLE_API ou https://VOTRE_CLE_API@maboutique.com/api/). C'est pratique pour un test rapide dans le navigateur, mais la documentation qualifie cette méthode de « très risquée » : l'URL, et donc la clé, finit dans l'historique du navigateur et dans les journaux des serveurs. À réserver aux essais, jamais en production. Dans tous les cas, appelez l'API en HTTPS.
Structure d'une URL du Webservice#
Une requête part toujours de l'adresse de la boutique, ajoute /api/, le nom de la ressource (et éventuellement un identifiant), puis les paramètres :
https://maboutique.com/api/{ressource}/{id}?param1=valeur1¶m2=valeur2Quelques adresses de départ utiles :
/api/: la liste des ressources auxquelles votre clé donne accès ;/api/products/42: le produit 42 ;/api/products?schema=blank: un modèle vide du produit, à remplir pour une création ;/api/products?schema=synopsis: le même modèle avec le type et les contraintes de chaque champ.
Les paramètres de liste en un coup d'œil#
| Paramètre | Rôle | Exemple |
|---|---|---|
output_format | Format de la réponse : XML par défaut, JSON sur demande | output_format=JSON |
display | Champs renvoyés : full pour tout, ou une liste | display=[id,reference,price] |
filter | Conditions sur un champ | filter[active]=[1] |
sort | Tri croissant ou décroissant, sur un ou plusieurs champs | sort=[id_DESC] |
limit | Nombre de résultats, avec décalage optionnel | limit=20,20 |
date | À ajouter (date=1) pour trier ou filtrer sur date_add ou date_upd | date=1 |
output_format : XML ou JSON#
Sans précision, le Webservice répond en XML. Ajoutez output_format=JSON pour recevoir du JSON, plus simple à exploiter avec json_decode() en PHP ou dans un outil comme Postman :
https://maboutique.com/api/products?output_format=JSON
Les créations et modifications (POST, PUT) se font en revanche en XML, au format donné par ?schema=blank.
display : ne demander que les champs utiles#
Sans display, une liste ne renvoie que les identifiants des ressources. display=full renvoie tous les champs, ce qui pèse vite lourd sur un gros catalogue avec plusieurs langues. Mieux vaut lister les champs nécessaires :
https://maboutique.com/api/products?output_format=JSON&display=[id,reference,name,price]
Seuls id, reference, name et price sont renvoyés : la réponse est plus légère et arrive plus vite, ce qui compte dès que l'on parcourt des centaines de produits.
filter : filtrer les résultats#
Un filtre s'écrit filter[champ]=condition, avec la valeur entre crochets. Les opérateurs disponibles :
| Besoin | Syntaxe | Équivalent SQL |
|---|---|---|
| Valeur exacte | filter[id]=[42] | id = 42 |
| Une valeur parmi plusieurs | filter[id]=[1|5|9] | id IN (1, 5, 9) |
| Intervalle | filter[price]=[20,1000] | price BETWEEN 20 AND 1000 |
| Commence par | filter[name]=[appl]% | name LIKE 'appl%' |
| Finit par | filter[email]=%[@gmail.com] | email LIKE '%@gmail.com' |
| Contient | filter[name]=%[tee]% | name LIKE '%tee%' |
La comparaison sur une valeur exacte ne tient pas compte des majuscules. Plusieurs filtres se combinent simplement : chacun ajoute une condition (un « ET »). Exemple, les clients dont l'adresse se termine par @gmail.com :
https://maboutique.com/api/customers?output_format=JSON&display=[id,firstname,lastname,email]&filter[email]=%[@gmail.com]
Attention à l'encodage : dans un navigateur, % et @ passent tels quels, mais dans un script, encodez les valeurs (avec http_build_query() en PHP, par exemple) pour qu'un % ne soit pas pris pour un caractère encodé.
sort : trier les données#
Le tri s'écrit sort=[champ_ASC] ou sort=[champ_DESC], et plusieurs critères se séparent par une virgule : sort=[lastname_ASC,id_DESC]. Pour trier sur la date de création (date_add) ou de modification (date_upd), ajoutez date=1 : sans lui, PrestaShop ignore ces deux champs.
https://maboutique.com/api/orders?output_format=JSON&display=[id,reference,total_paid,date_add]&sort=[date_add_DESC]&date=1
Les commandes arrivent de la plus récente à la plus ancienne : combiné avec limit, c'est le moyen le plus simple de ne traiter que les dernières.
limit : paginer les résultats#
limit=20 renvoie les 20 premiers résultats ; limit=20,20 saute les 20 premiers (le décalage commence à 0) et renvoie les 20 suivants. Pour parcourir tout un catalogue, augmentez le décalage de la taille de la page jusqu'à recevoir une réponse vide :
https://maboutique.com/api/products?output_format=JSON&display=[id,reference]&sort=[id_ASC]&limit=0,100 https://maboutique.com/api/products?output_format=JSON&display=[id,reference]&sort=[id_ASC]&limit=100,100
Triez toujours sur un champ stable (l'identifiant, par exemple) quand vous paginez : sans tri, l'ordre des résultats n'est pas garanti d'une page à l'autre.
Exemples d'URL qui combinent plusieurs paramètres#
Les 50 derniers produits actifs entre 20 et 1 000 €#
https://maboutique.com/api/products?output_format=JSON&display=[id,reference,name,price,active]&filter[active]=[1]&filter[price]=[20,1000]&sort=[id_DESC]&limit=50
Typiquement la requête qui alimente un comparateur de prix ou un catalogue externe. Le prix renvoyé est le prix de base hors taxes du produit, sans les réductions.
Les commandes d'un mois, de la plus ancienne à la plus récente#
https://maboutique.com/api/orders?output_format=JSON&display=[id,reference,id_customer,total_paid,date_add]&filter[date_add]=[2026-10-01 00:00:00,2026-10-31 23:59:59]&date=1&sort=[date_add_ASC]
Pratique pour une synchronisation comptable ou logistique : les commandes arrivent dans l'ordre de passage. Pensez au paramètre date=1, indispensable pour filtrer sur date_add.
Les 100 premiers clients avec une adresse Gmail#
https://maboutique.com/api/customers?output_format=JSON&display=[id,firstname,lastname,email]&filter[email]=%[@gmail.com]&limit=100
Exemples en PHP avec cURL#
Les exemples suivants utilisent l'authentification recommandée (clé dans l'en-tête) et http_build_query() pour encoder correctement les paramètres.
Lister des produits en JSON#
$shopUrl = 'https://maboutique.com'; $apiKey = 'VOTRE_CLE_API'; $query = http_build_query([ 'output_format' => 'JSON', 'display' => '[id,reference,name,price]', 'filter[active]' => '[1]', 'sort' => '[id_ASC]', 'limit' => '0,50', 'language' => 1, // une seule langue : name devient une simple chaîne ]); $ch = curl_init($shopUrl . '/api/products?' . $query); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_USERPWD => $apiKey . ':', CURLOPT_HTTPAUTH => CURLAUTH_BASIC, ]); $response = curl_exec($ch); $status = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($response === false || $status !== 200) { throw new RuntimeException('Appel API en échec (HTTP ' . $status . ')'); } $data = json_decode($response, true); foreach ($data['products'] ?? [] as $product) { echo $product['id'] . ' - ' . $product['reference'] . ' - ' . $product['name'] . ' - ' . $product['price'] . PHP_EOL; }
Sans le paramètre language, les champs traduits comme name arrivent sous forme de liste (une entrée par langue, avec id et value). La clé products n'existe que si la requête renvoie au moins un résultat : une réponse vide se traduit par un tableau vide.
Lire le détail d'un produit#
$productId = 123; $ch = curl_init($shopUrl . '/api/products/' . $productId . '?output_format=JSON&language=1'); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_USERPWD => $apiKey . ':', CURLOPT_HTTPAUTH => CURLAUTH_BASIC, ]); $product = json_decode(curl_exec($ch), true)['product'] ?? null; curl_close($ch); echo 'Nom : ' . $product['name'] . PHP_EOL; echo 'Prix HT : ' . $product['price'] . PHP_EOL;
Créer un produit (POST)#
Une création s'envoie en XML. Partez du modèle renvoyé par /api/products?schema=blank, remplissez les champs voulus et envoyez-le en POST :
$xml = <<<XML <?xml version="1.0" encoding="UTF-8"?> <prestashop xmlns:xlink="http://www.w3.org/1999/xlink"> <product> <id_category_default>2</id_category_default> <price>29.90</price> <active>1</active> <name><language id="1">Tee-shirt API</language></name> <link_rewrite><language id="1">tee-shirt-api</language></link_rewrite> </product> </prestashop> XML; $ch = curl_init($shopUrl . '/api/products'); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_USERPWD => $apiKey . ':', CURLOPT_HTTPAUTH => CURLAUTH_BASIC, CURLOPT_POST => true, CURLOPT_HTTPHEADER => ['Content-Type: application/xml'], CURLOPT_POSTFIELDS => $xml, ]); $response = curl_exec($ch); $status = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); // 201 = produit créé ; la réponse XML contient le produit avec son nouvel identifiant $created = new SimpleXMLElement($response); echo 'HTTP ' . $status . ', produit n° ' . $created->product->id . PHP_EOL;
Modifier un produit (PUT)#
Une modification renvoie la ressource complète : on lit le produit en XML, on change les champs voulus, on retire les champs en lecture seule, puis on renvoie le tout en PUT.
$productId = 123; $auth = [CURLOPT_USERPWD => $apiKey . ':', CURLOPT_HTTPAUTH => CURLAUTH_BASIC, CURLOPT_RETURNTRANSFER => true]; // 1. Lire le produit en XML $ch = curl_init($shopUrl . '/api/products/' . $productId); curl_setopt_array($ch, $auth); $xml = new SimpleXMLElement(curl_exec($ch)); curl_close($ch); // 2. Modifier le prix et retirer les champs en lecture seule (sinon : erreur 400) $xml->product->price = '34.90'; unset($xml->product->manufacturer_name, $xml->product->quantity); // 3. Renvoyer le produit complet en PUT $ch = curl_init($shopUrl . '/api/products/' . $productId); curl_setopt_array($ch, $auth + [ CURLOPT_CUSTOMREQUEST => 'PUT', CURLOPT_HTTPHEADER => ['Content-Type: application/xml'], CURLOPT_POSTFIELDS => $xml->asXML(), ]); curl_exec($ch); echo 'HTTP ' . curl_getinfo($ch, CURLINFO_HTTP_CODE) . PHP_EOL; // 200 = modifié curl_close($ch);
Les stocks ne se modifient pas sur le produit : ils passent par la ressource stock_availables.
L'API Admin de PrestaShop 9#
Construite sur le framework API Platform, l'API Admin est activée par défaut dans PrestaShop 9. Elle fonctionne avec des clients : chacun reçoit un identifiant, un secret et une liste de droits (les scopes), et obtient un jeton temporaire avant chaque série d'appels.
- Créer un client : dans Paramètres avancés > Admin API, cliquez sur « Ajouter un client API », choisissez sa description, ses scopes et la durée de vie de ses jetons. Le secret ne s'affiche qu'une seule fois : copiez-le aussitôt.
- Obtenir un jeton : envoyez l'identifiant et le secret au point d'accès
/admin-api/access_token. - Appeler l'API avec ce jeton dans l'en-tête
Authorization: Bearer.
curl -X POST https://maboutique.com/admin-api/access_token \ -d grant_type=client_credentials \ -d client_id=VOTRE_CLIENT_ID \ -d client_secret=VOTRE_SECRET \ -d scope=product_read curl https://maboutique.com/admin-api/products \ -H "Authorization: Bearer VOTRE_JETON"
Un appel sans le scope nécessaire est refusé avec une erreur 403 « Invalid scope » (par exemple, product_read pour lire les produits). La liste complète des points d'accès de votre boutique se consulte sur /admin-api/docs.html. L'API Admin exige HTTPS en production.
Les erreurs les plus fréquentes#
| Réponse | Cause probable | Solution |
|---|---|---|
| 401 Unauthorized | Clé absente, erronée ou désactivée ; Webservice désactivé | Vérifier la clé et l'option « Activer le service web » |
| 401 avec Apache en mode CGI/FastCGI | L'en-tête Authorization n'est pas transmis à PHP | Activer la réécriture d'URL, ou passer la clé dans l'URL le temps du diagnostic |
| 403 Forbidden | La clé n'a pas le droit demandé sur cette ressource | Cocher la méthode (GET, POST…) pour la ressource dans la clé |
| 403 « Invalid scope » (API Admin) | Le client n'a pas le scope du point d'accès | Ajouter le scope au client et redemander un jeton |
| 400 Bad Request sur un PUT | Champ en lecture seule renvoyé, ou champ obligatoire manquant | Retirer manufacturer_name, quantity ; comparer avec ?schema=synopsis |
Filtre ou tri sur date_add / date_upd refusé ou ignoré | Paramètre date=1 absent | Ajouter &date=1 |
Bonnes pratiques#
- Toujours en HTTPS, avec la clé dans l'en-tête plutôt que dans l'URL.
- Une clé par outil, limitée aux ressources et aux méthodes nécessaires (lecture seule pour un comparateur, écriture sur les commandes seulement pour un ERP).
- Des réponses légères : combinez
display,filteretlimitplutôt que de tout télécharger. - Une pagination triée sur l'identifiant pour parcourir un gros catalogue sans doublon ni oubli.
- Des journaux d'erreurs : conservez le code HTTP et le corps de la réponse en cas d'échec, ils indiquent presque toujours le champ en cause.
- Des essais en préproduction avant tout POST, PUT ou DELETE sur la boutique en ligne.
Besoin d'un coup de main ? Websource développe et maintient des boutiques PrestaShop et leurs connexions (ERP, CRM, marketplaces) : voir notre agence PrestaShop. Notre hébergement PrestaShop inclut HTTPS, PHP réglable par extension et l'accompagnement de notre équipe dès la commande.
Pour aller plus loin, la documentation officielle détaille chaque ressource : Webservice PrestaShop et API Admin de PrestaShop 9. Si votre projet consiste à importer un catalogue complet, notre guide Importer un catalogue produits dans PrestaShop compare l'API aux autres méthodes.







