L'intégration d'API tierces dans Prestashop permet d'enrichir les fonctionnalités de votre boutique en connectant des services externes : paiement, logistique, CRM, marketing, etc. Ce guide vous montre comment intégrer proprement des API dans votre boutique Prestashop.
1. Comprendre les types d'API
Avant de commencer l'intégration, il est important de comprendre les différents types d'API que vous rencontrerez.
API REST
Le type d'API le plus courant en 2025. Utilise les méthodes HTTP (GET, POST, PUT, DELETE) et retourne généralement du JSON.
API SOAP
API plus anciennes basées sur XML. Encore utilisées par certains systèmes legacy d'ERP ou de logistique.
Webhooks
Notifications push envoyées par un service externe vers votre boutique lors d'événements spécifiques.
2. Créer un service API réutilisable
Créez une classe de service pour centraliser vos appels API et faciliter la maintenance.
<?php
/**
* Service générique pour les appels API
*/
class ApiService
{
private $apiUrl;
private $apiKey;
private $timeout = 30;
/**
* Constructeur du service API
*
* @param string $apiUrl URL de base de l'API
* @param string $apiKey Clé d'authentification
*/
public function __construct(string $apiUrl, string $apiKey)
{
$this->apiUrl = rtrim($apiUrl, '/');
$this->apiKey = $apiKey;
}
/**
* Effectuer une requête GET
*
* @param string $endpoint Endpoint de l'API
* @param array $params Paramètres de requête
* @return array|false Réponse décodée ou false
*/
public function get(string $endpoint, array $params = [])
{
$url = $this->apiUrl . '/' . ltrim($endpoint, '/');
if (!empty($params)) {
$url .= '?' . http_build_query($params);
}
return $this->executeRequest($url, 'GET');
}
/**
* Effectuer une requête POST
*
* @param string $endpoint Endpoint de l'API
* @param array $data Données à envoyer
* @return array|false Réponse décodée ou false
*/
public function post(string $endpoint, array $data = [])
{
$url = $this->apiUrl . '/' . ltrim($endpoint, '/');
return $this->executeRequest($url, 'POST', $data);
}
/**
* Effectuer une requête PUT
*
* @param string $endpoint Endpoint de l'API
* @param array $data Données à envoyer
* @return array|false Réponse décodée ou false
*/
public function put(string $endpoint, array $data = [])
{
$url = $this->apiUrl . '/' . ltrim($endpoint, '/');
return $this->executeRequest($url, 'PUT', $data);
}
/**
* Effectuer une requête DELETE
*
* @param string $endpoint Endpoint de l'API
* @return array|false Réponse décodée ou false
*/
public function delete(string $endpoint)
{
$url = $this->apiUrl . '/' . ltrim($endpoint, '/');
return $this->executeRequest($url, 'DELETE');
}
/**
* Exécuter une requête HTTP
*
* @param string $url URL complète
* @param string $method Méthode HTTP
* @param array $data Données à envoyer
* @return array|false Réponse décodée ou false
*/
private function executeRequest(string $url, string $method, array $data = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
$headers = [
'Authorization: Bearer ' . $this->apiKey,
'Content-Type: application/json',
'Accept: application/json'
];
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
if (in_array($method, ['POST', 'PUT']) && !empty($data)) {
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
}
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);
if ($error) {
PrestaShopLogger::addLog(
'API Request Error: ' . $error,
3,
null,
'ApiService'
);
return false;
}
if ($httpCode >= 400) {
PrestaShopLogger::addLog(
'API HTTP Error ' . $httpCode . ': ' . $response,
3,
null,
'ApiService'
);
return false;
}
return json_decode($response, true);
}
}
3. Exemple : Intégration d'une API de paiement
Voyons comment intégrer une API de paiement (Stripe, PayPal, etc.) dans un module Prestashop.
<?php
/**
* Module d'intégration API de paiement
*/
class PaymentApiModule extends PaymentModule
{
private $apiService;
public function __construct()
{
$this->name = 'paymentapi';
$this->tab = 'payments_gateways';
$this->version = '1.0.0';
$this->author = 'Votre Nom';
parent::__construct();
$this->displayName = $this->l('API Payment Gateway');
$this->description = $this->l('Intégration API de paiement');
// Initialiser le service API
$apiUrl = Configuration::get('PAYMENT_API_URL');
$apiKey = Configuration::get('PAYMENT_API_KEY');
if ($apiUrl && $apiKey) {
$this->apiService = new ApiService($apiUrl, $apiKey);
}
}
/**
* Créer un paiement via l'API
*
* @param Cart $cart Panier actuel
* @return array|false Résultat de l'API
*/
public function createPayment(Cart $cart)
{
$customer = new Customer($cart->id_customer);
$currency = new Currency($cart->id_currency);
$total = (float)$cart->getOrderTotal(true, Cart::BOTH);
$paymentData = [
'amount' => $total,
'currency' => $currency->iso_code,
'customer' => [
'email' => $customer->email,
'firstname' => $customer->firstname,
'lastname' => $customer->lastname
],
'order_reference' => $this->generateOrderReference($cart),
'callback_url' => $this->context->link->getModuleLink(
$this->name,
'callback',
[],
true
)
];
try {
$response = $this->apiService->post('payments', $paymentData);
if ($response && isset($response['payment_url'])) {
// Sauvegarder la transaction
$this->saveTransaction($cart->id, $response);
return $response;
}
return false;
} catch (Exception $e) {
PrestaShopLogger::addLog(
'Payment API Error: ' . $e->getMessage(),
3,
null,
'PaymentApiModule'
);
return false;
}
}
/**
* Sauvegarder une transaction en base de données
*
* @param int $idCart ID du panier
* @param array $apiResponse Réponse de l'API
* @return bool Succès de la sauvegarde
*/
private function saveTransaction(int $idCart, array $apiResponse): bool
{
$sql = 'INSERT INTO `' . _DB_PREFIX_ . 'payment_api_transaction`
(id_cart, transaction_id, payment_url, status, date_add)
VALUES (
' . (int)$idCart . ',
"' . pSQL($apiResponse['transaction_id']) . '",
"' . pSQL($apiResponse['payment_url']) . '",
"pending",
NOW()
)';
return Db::getInstance()->execute($sql);
}
/**
* Générer une référence de commande unique
*
* @param Cart $cart Le panier
* @return string Référence unique
*/
private function generateOrderReference(Cart $cart): string
{
return 'ORDER-' . $cart->id . '-' . time();
}
}
4. Gérer les webhooks entrants
Les webhooks permettent aux API tierces de notifier votre boutique d'événements en temps réel.
<?php
/**
* Contrôleur pour recevoir les webhooks
*/
class PaymentApiWebhookModuleFrontController extends ModuleFrontController
{
/**
* Traiter le webhook entrant
*/
public function postProcess()
{
// Récupérer le payload brut
$payload = file_get_contents('php://input');
$data = json_decode($payload, true);
// Vérifier la signature du webhook
if (!$this->verifyWebhookSignature($payload)) {
PrestaShopLogger::addLog(
'Webhook signature verification failed',
3,
null,
'PaymentApiWebhook'
);
http_response_code(403);
die('Unauthorized');
}
// Traiter l'événement
$this->processWebhookEvent($data);
// Répondre rapidement au webhook
http_response_code(200);
die('OK');
}
/**
* Vérifier la signature du webhook
*
* @param string $payload Payload brut
* @return bool Signature valide
*/
private function verifyWebhookSignature(string $payload): bool
{
$signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
$secret = Configuration::get('PAYMENT_API_WEBHOOK_SECRET');
$expectedSignature = hash_hmac('sha256', $payload, $secret);
return hash_equals($expectedSignature, $signature);
}
/**
* Traiter l'événement du webhook
*
* @param array $data Données du webhook
*/
private function processWebhookEvent(array $data)
{
$eventType = $data['event_type'] ?? '';
$transactionId = $data['transaction_id'] ?? '';
switch ($eventType) {
case 'payment.success':
$this->handlePaymentSuccess($transactionId, $data);
break;
case 'payment.failed':
$this->handlePaymentFailed($transactionId, $data);
break;
case 'payment.refunded':
$this->handlePaymentRefunded($transactionId, $data);
break;
default:
PrestaShopLogger::addLog(
'Unknown webhook event: ' . $eventType,
2,
null,
'PaymentApiWebhook'
);
}
}
/**
* Gérer un paiement réussi
*
* @param string $transactionId ID de transaction
* @param array $data Données du webhook
*/
private function handlePaymentSuccess(string $transactionId, array $data)
{
// Récupérer la transaction
$query = new DbQuery();
$query->select('id_cart')
->from('payment_api_transaction')
->where('transaction_id = "' . pSQL($transactionId) . '"');
$result = Db::getInstance()->getRow($query);
if (!$result) {
return;
}
$idCart = (int)$result['id_cart'];
$cart = new Cart($idCart);
// Valider la commande
$this->module->validateOrder(
$idCart,
Configuration::get('PS_OS_PAYMENT'),
$cart->getOrderTotal(),
$this->module->displayName,
null,
['transaction_id' => $transactionId],
null,
false,
$cart->secure_key
);
// Mettre à jour le statut de la transaction
Db::getInstance()->update(
'payment_api_transaction',
['status' => 'completed'],
'transaction_id = "' . pSQL($transactionId) . '"'
);
}
}
5. Intégration d'une API logistique (transporteur)
Connectez votre boutique à des API de transporteurs pour calculer les frais de port en temps réel.
<?php
/**
* Module transporteur avec API
*/
class ShippingApiCarrier extends CarrierModule
{
private $apiService;
public function getOrderShippingCost($params, $shippingCost)
{
$cart = $params;
$address = new Address($cart->id_address_delivery);
// Préparer les données pour l'API
$shipmentData = [
'origin' => [
'country' => Configuration::get('PS_SHOP_COUNTRY_ID'),
'postal_code' => Configuration::get('PS_SHOP_CODE')
],
'destination' => [
'country' => $address->id_country,
'postal_code' => $address->postcode,
'city' => $address->city
],
'package' => [
'weight' => $cart->getTotalWeight(),
'value' => $cart->getOrderTotal()
]
];
try {
// Appeler l'API du transporteur
$response = $this->apiService->post('rates/calculate', $shipmentData);
if ($response && isset($response['rate'])) {
return (float)$response['rate'];
}
// Retourner un tarif par défaut en cas d'erreur
return (float)Configuration::get('SHIPPING_API_DEFAULT_RATE');
} catch (Exception $e) {
PrestaShopLogger::addLog(
'Shipping API Error: ' . $e->getMessage(),
3,
null,
'ShippingApiCarrier'
);
return false;
}
}
/**
* Créer une étiquette d'expédition via l'API
*
* @param Order $order Commande à expédier
* @return array|false Données de l'étiquette
*/
public function createShippingLabel(Order $order)
{
$address = new Address($order->id_address_delivery);
$customer = new Customer($order->id_customer);
$labelData = [
'order_reference' => $order->reference,
'recipient' => [
'name' => $address->firstname . ' ' . $address->lastname,
'company' => $address->company,
'address1' => $address->address1,
'address2' => $address->address2,
'postal_code' => $address->postcode,
'city' => $address->city,
'country' => Country::getIsoById($address->id_country),
'phone' => $address->phone,
'email' => $customer->email
],
'package' => [
'weight' => $order->getTotalWeight(),
'value' => $order->total_paid
]
];
$response = $this->apiService->post('labels/create', $labelData);
if ($response && isset($response['label_url'])) {
// Sauvegarder les informations du colis
$this->saveTrackingInfo($order->id, $response);
return $response;
}
return false;
}
/**
* Sauvegarder les informations de tracking
*
* @param int $idOrder ID de la commande
* @param array $trackingData Données de tracking
* @return bool Succès
*/
private function saveTrackingInfo(int $idOrder, array $trackingData): bool
{
$orderCarrier = new OrderCarrier($idOrder);
$orderCarrier->tracking_number = pSQL($trackingData['tracking_number']);
$orderCarrier->update();
// Envoyer l'email de confirmation d'expédition au client
$this->sendTrackingEmail($idOrder, $trackingData['tracking_number']);
return true;
}
}
6. Intégration CRM et Marketing
Synchronisez vos clients et commandes avec votre CRM ou outil de marketing automation.
<?php
/**
* Synchroniser les clients avec un CRM via API
*/
class CrmSyncService
{
private $apiService;
public function __construct(ApiService $apiService)
{
$this->apiService = $apiService;
}
/**
* Synchroniser un client après création
*
* @param Customer $customer Le client à synchroniser
* @return bool Succès de la synchronisation
*/
public function syncCustomer(Customer $customer): bool
{
$customerData = [
'email' => $customer->email,
'firstname' => $customer->firstname,
'lastname' => $customer->lastname,
'birthday' => $customer->birthday,
'newsletter' => (bool)$customer->newsletter,
'created_at' => $customer->date_add,
'external_id' => $customer->id
];
$response = $this->apiService->post('contacts', $customerData);
if ($response && isset($response['id'])) {
// Sauvegarder l'ID CRM
Configuration::updateValue(
'CRM_CUSTOMER_ID_' . $customer->id,
$response['id']
);
return true;
}
return false;
}
/**
* Synchroniser une commande
*
* @param Order $order La commande à synchroniser
* @return bool Succès
*/
public function syncOrder(Order $order): bool
{
$customer = new Customer($order->id_customer);
$crmCustomerId = Configuration::get('CRM_CUSTOMER_ID_' . $customer->id);
if (!$crmCustomerId) {
// Synchroniser le client d'abord
$this->syncCustomer($customer);
$crmCustomerId = Configuration::get('CRM_CUSTOMER_ID_' . $customer->id);
}
$orderData = [
'contact_id' => $crmCustomerId,
'reference' => $order->reference,
'total' => $order->total_paid,
'currency' => Currency::getCurrencyInstance($order->id_currency)->iso_code,
'status' => $order->getCurrentStateFull($order->id_lang)['name'],
'created_at' => $order->date_add,
'items' => $this->getOrderItems($order)
];
$response = $this->apiService->post('orders', $orderData);
return $response !== false;
}
/**
* Récupérer les articles de la commande
*
* @param Order $order La commande
* @return array Articles formatés
*/
private function getOrderItems(Order $order): array
{
$items = [];
$products = $order->getProducts();
foreach ($products as $product) {
$items[] = [
'sku' => $product['product_reference'],
'name' => $product['product_name'],
'quantity' => (int)$product['product_quantity'],
'price' => (float)$product['unit_price_tax_incl']
];
}
return $items;
}
}
7. Gestion des erreurs et retry logic
Les API peuvent être indisponibles temporairement. Implémentez une logique de retry pour les opérations critiques.
<?php
/**
* Ajouter une logique de retry aux appels API
*/
trait ApiRetryTrait
{
/**
* Exécuter une requête avec retry
*
* @param callable $apiCall Fonction d'appel API
* @param int $maxRetries Nombre maximum de tentatives
* @param int $delayMs Délai entre les tentatives (ms)
* @return mixed Résultat de l'API
*/
protected function executeWithRetry(
callable $apiCall,
int $maxRetries = 3,
int $delayMs = 1000
) {
$attempt = 0;
while ($attempt < $maxRetries) {
try {
$result = $apiCall();
if ($result !== false) {
return $result;
}
} catch (Exception $e) {
PrestaShopLogger::addLog(
"API retry attempt {$attempt}: " . $e->getMessage(),
2
);
}
$attempt++;
if ($attempt < $maxRetries) {
usleep($delayMs * 1000);
}
}
return false;
}
}
// Utilisation
class MyApiModule extends Module
{
use ApiRetryTrait;
public function callExternalApi()
{
return $this->executeWithRetry(function () {
return $this->apiService->get('endpoint');
}, 3, 2000);
}
}
8. Cache des réponses API
Évitez les appels redondants en cachant les réponses API quand c'est pertinent.
<?php
/**
* Wrapper avec cache pour les appels API
*/
class CachedApiService
{
private $apiService;
private $cacheTtl = 3600; // 1 heure
/**
* Récupérer des données avec cache
*
* @param string $cacheKey Clé de cache
* @param callable $apiCall Fonction d'appel API
* @return mixed Données de l'API
*/
public function getCached(string $cacheKey, callable $apiCall)
{
// Vérifier le cache
$cached = Cache::retrieve($cacheKey);
if ($cached !== false) {
return json_decode($cached, true);
}
// Appeler l'API
$result = $apiCall();
if ($result !== false) {
// Sauvegarder en cache
Cache::store($cacheKey, json_encode($result));
}
return $result;
}
}
// Exemple d'utilisation
$cachedApi = new CachedApiService($apiService);
$rates = $cachedApi->getCached('shipping_rates_' . $postcode, function () use ($apiService) {
return $apiService->get('rates/calculate');
});
9. Tester vos intégrations API
Testez toujours vos intégrations API avant de les déployer en production.
- Utilisez des environnements sandbox fournis par les API
- Testez les cas d'erreur (timeout, 404, 500, etc.)
- Vérifiez les limites de taux (rate limiting)
- Testez avec des données réalistes
- Documentez les endpoints utilisés
10. Sécurité des intégrations API
Protégez vos clés API et sécurisez vos endpoints.
- Stockez les clés API dans Configuration, jamais en dur dans le code
- Utilisez HTTPS pour tous les appels
- Validez les signatures des webhooks
- Limitez les permissions des clés API au strict nécessaire
- Loggez les erreurs mais pas les données sensibles
- Implémentez un rate limiting sur vos webhooks
Conclusion
L'intégration d'API tierces ouvre des possibilités infinies pour enrichir votre boutique Prestashop. En suivant ces bonnes pratiques, vous créerez des intégrations robustes, maintenables et sécurisées qui apporteront de la valeur à vos clients.
Besoin d'aide pour intégrer une API spécifique dans votre boutique Prestashop ? Contactez-moi pour discuter de votre projet d'intégration !