PrestaShop Webservice API: integracja REST i ERP
Kompletny przewodnik po PrestaShop Webservice API — operacje CRUD, biblioteka PHP, uwierzytelnianie, filtrowanie, integracja ERP/POS i AdminAPI w PS 9.
Czym jest PrestaShop Webservice
PrestaShop Webservice to wbudowane API typu REST, które umożliwia zewnętrznym aplikacjom odczytywanie i zapisywanie danych sklepu przez HTTP. Udostępnia zasoby (produkty, zamówienia, klientów, kategorie, stany magazynowe i dziesiątki innych) poprzez ustandaryzowany interfejs. Domyślnym formatem jest XML; JSON jest dostępny w PS 1.7+ za pomocą parametru &output_format=JSON.
Każdy PrestaShop od wersji 1.4 zawiera Webservice. To nie jest moduł — to część rdzenia systemu. PS 1.6, 1.7, 8.x i 9.x — wszystkie go obsługują.
Webservice to oficjalny sposób integracji PrestaShop z zewnętrznymi systemami. Bezpośrednie zapytania do bazy danych pomijają walidację, hooki i logikę biznesową. API tego nie robi.
Typowe zastosowania: synchronizacja produktów z ERP lub PIM, eksport zamówień do systemów realizacji, utrzymywanie spójności stanów magazynowych między kanałami, zarządzanie klientami z CRM oraz automatyzacja operacji masowych, takich jak aktualizacja cen.
Włączanie i konfiguracja API
Webservice jest domyślnie wyłączony. Włącz go w Zaawansowane > Webservice, a następnie kliknij „Dodaj nowy klucz webservice”. Dla każdego klucza ustawiasz opis, status włączony/wyłączony oraz macierz uprawnień — siatkę zasobów i dozwolonych metod HTTP (GET, POST, PUT, DELETE, HEAD).
Twórz oddzielne klucze API dla każdej integracji. Jeśli Twój ERP tylko odczytuje zamówienia i aktualizuje stany magazynowe, nie dawaj mu uprawnień do usuwania produktów. Zasada minimalnych uprawnień.
Webservice wymaga przepisywania URL-i. Apache obsługuje to przez .htaccess w /api/. W przypadku Nginx dodaj:
location /api/ {
try_files $uri $uri/ /webservice/dispatcher.php?$args;
}
Uwierzytelnianie
HTTP Basic Auth — klucz API wpisuje się w pole nazwy użytkownika, hasło pozostaje puste:
curl -u "YOUR_API_KEY:" https://your-store.com/api/products
HTTPS jest obowiązkowy — klucze są przesyłane w każdym nagłówku żądania. Biała lista IP to najskuteczniejszy pojedynczy środek bezpieczeństwa dla integracji ze stałym adresem IP:
# .htaccess in /api/
<IfModule mod_authz_core.c>
Require ip 10.0.0.5
Require ip 192.168.1.0/24
</IfModule>
Rotuj klucze co 6-12 miesięcy. Przechowuj je w zmiennych środowiskowych, nigdy w kodzie źródłowym.
Dostępne zasoby
Wywołaj główny endpoint, aby zobaczyć wszystko, do czego Twój klucz ma dostęp:
curl -u "KEY:" https://your-store.com/api/
Gotowy do skopiowania smoke test API
Zanim napiszesz pełną integrację, sprawdź z serwera, który będzie uruchamiał synchronizację, czy działają klucz, reguły przepisywania URL, format wyjścia i podstawowe zasoby:
#!/usr/bin/env bash
set -euo pipefail
BASE="${PRESTASHOP_URL%/}"
KEY="${PRESTASHOP_WS_KEY:?Set PRESTASHOP_WS_KEY first}"
curl -fsS -u "$KEY:" "$BASE/api/?output_format=JSON" >/tmp/ps-api-root.json
curl -fsS -u "$KEY:" "$BASE/api/products?display=[id,reference,active]&limit=5&output_format=JSON" >/tmp/ps-api-products.json
curl -fsS -u "$KEY:" "$BASE/api/stock_availables?display=[id,id_product,id_product_attribute,quantity]&limit=5&output_format=JSON" >/tmp/ps-api-stock.json
echo "Webservice key, rewrite rules and read permissions are working."Jeśli pierwsze żądanie działa, ale żądania produktów lub stanów magazynowych nie, Webservice jest osiągalny; problem prawie zawsze leży w macierzy uprawnień klucza.
Katalog: products, combinations, categories, manufacturers, suppliers, product_features, product_feature_values, product_options (grupy atrybutów), product_option_values, tags, images
Sprzedaż: orders, order_details (pozycje zamówienia), order_states, order_histories (zmiany statusów), order_carriers (śledzenie przesyłek), carts, cart_rules
Klienci: customers, addresses, groups
Magazyn: stock_availables (główny zasób magazynowy), warehouses, supply_orders
Konfiguracja: carriers, countries, currencies, languages, taxes, zones, shops
Operacje CRUD
GET — Odczyt danych
# List products (IDs only)
curl -u "KEY:" https://your-store.com/api/products
# Full details
curl -u "KEY:" "https://your-store.com/api/products?display=full"
# Selected fields only (faster)
curl -u "KEY:" "https://your-store.com/api/products?display=[id,name,price,reference]"
# Single product in JSON
curl -u "KEY:" "https://your-store.com/api/products/42?output_format=JSON"
POST — Tworzenie
Pobierz pusty schemat XML, wypełnij wymagane pola i wyślij go z powrotem metodą POST:
curl -u "KEY:" -X POST -H "Content-Type: application/xml" \
-d '<prestashop xmlns:xlink="http://www.w3.org/1999/xlink">
<product>
<id_category_default>2</id_category_default>
<id_tax_rules_group>1</id_tax_rules_group>
<active>1</active><state>1</state>
<price>29.99</price>
<name><language id="1">My Product</language></name>
<link_rewrite><language id="1">my-product</language></link_rewrite>
<description_short><language id="1">Short desc</language></description_short>
<associations><categories><category><id>2</id></category></categories></associations>
</product>
</prestashop>' https://your-store.com/api/products
PUT — Aktualizacja
Pobierz aktualny zasób metodą GET, zmodyfikuj pola i wyślij cały XML z powrotem metodą PUT. Częściowe aktualizacje nie są obsługiwane.
curl -u "KEY:" https://your-store.com/api/products/42 -o product.xml
# Edit product.xml, then:
curl -u "KEY:" -X PUT -H "Content-Type: application/xml" \
-d @product.xml https://your-store.com/api/products/42
Zawsze wykonaj GET przed PUT. Jeśli skonstruujesz XML od zera i zapomnisz wymaganego pola, API może je wyczyścić lub odrzucić żądanie.
DELETE
curl -u "KEY:" -X DELETE https://your-store.com/api/products/42
# Multiple: DELETE "https://your-store.com/api/products/?id=[42|43|44]"
DELETE jest trwałe — bez kosza, bez cofania. W środowisku produkcyjnym lepiej ustawić active=0.
Filtrowanie, sortowanie i paginacja
# Exact match
?filter[reference]=ABC-123
# Range (price 10-50)
?filter[price]=[10,50]
# Date range
?filter[date_upd]=[2025-01-01,2025-12-31]
# Starts with (% URL-encoded as %25)
?filter[name]=[Nike]%25
# Combined
?filter[active]=1&filter[id_category_default]=5&display=[id,name,price]
# Sorting
?sort=[price_ASC] ?sort=[date_upd_DESC]
# Pagination (offset,count)
?limit=50 # first 50
?limit=50,50 # results 51-100
Odkrywanie schematu — dwa tryby pozwalają zbadać strukturę zasobu bez dokumentacji:
?schema=blank # Empty XML template with all fields
?schema=synopsis # Field types, required flags, max lengths, read-only markers
Synopsis powie Ci dokładnie, które pola są wymagane i jakiego formatu oczekują. Zawsze sięgaj do niego przed pisaniem kodu integracji.
Praca z obrazami
Obrazy produktów są przesyłane za pomocą danych multipart do osobnego endpointu:
# Upload
curl -u "KEY:" -X POST -F "image=@photo.jpg;type=image/jpeg" \
"https://your-store.com/api/images/products/42"
# List images for product
curl -u "KEY:" "https://your-store.com/api/images/products/42"
# Get specific image / image type
curl -u "KEY:" "https://your-store.com/api/images/products/42/15/large_default"
# Delete
curl -u "KEY:" -X DELETE "https://your-store.com/api/images/products/42/15"
Przesyłanie w PHP:
$ch = curl_init("$shopUrl/api/images/products/$productId");
curl_setopt($ch, CURLOPT_USERPWD, "$apiKey:");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, [
'image' => new CURLFile($imagePath, mime_content_type($imagePath))
]);
$response = curl_exec($ch);
Optymalizuj obrazy przed przesyłaniem. Zmniejsz do maksymalnie 2048px i skompresuj — zdjęcia 5MB z lustrzanki spowolnią Twój sklep.
Kombinacje i atrybuty
Kombinacje to najtrudniejsza część API. Model danych ma trzy warstwy:
- Product Option (grupa atrybutów) — Rozmiar, Kolor, Materiał
- Product Option Value — S, M, L, Czerwony, Niebieski
- Combination — zestaw wartości dla produktu (Rozmiar:M + Kolor:Czerwony)
Tworzenie w kolejności: grupa atrybutów → wartości → kombinacja:
# Create combination linking to existing attribute values
curl -u "KEY:" -X POST -H "Content-Type: application/xml" \
-d '<prestashop><combination>
<id_product>42</id_product>
<reference>PROD-42-M-RED</reference>
<price>5.00</price>
<minimal_quantity>1</minimal_quantity>
<associations><product_option_values>
<product_option_value><id>2</id></product_option_value>
<product_option_value><id>7</id></product_option_value>
</product_option_values></associations>
</combination></prestashop>' "https://your-store.com/api/combinations"
Pole price w kombinacji to wpływ na cenę dodawany do bazowej ceny produktu, a nie cena końcowa.
Stan magazynowy per kombinacja
Stan magazynowy jest zarządzany przez stock_availables, a nie przez samą kombinację:
# Find stock record
curl -u "KEY:" "https://your-store.com/api/stock_availables?filter[id_product]=42&filter[id_product_attribute]=15&display=full"
# Update (GET first, modify quantity, PUT back)
curl -u "KEY:" -X PUT -H "Content-Type: application/xml" \
-d '<prestashop><stock_available>
<id>89</id><id_product>42</id_product>
<id_product_attribute>15</id_product_attribute>
<quantity>100</quantity>
</stock_available></prestashop>' "https://your-store.com/api/stock_availables/89"
Rekord magazynowy na poziomie produktu (id_product_attribute=0) przechowuje sumę wszystkich kombinacji. Aktualizuj stan magazynowy na poziomie kombinacji, a PrestaShop automatycznie przeliczy sumę.
Zamówienia i koszyk
# Recent orders
curl -u "KEY:" "https://your-store.com/api/orders?display=[id,reference,total_paid,current_state,date_add]&sort=[id_DESC]&limit=20"
# Full order with line items
curl -u "KEY:" "https://your-store.com/api/orders/1234?display=full"
curl -u "KEY:" "https://your-store.com/api/order_details?filter[id_order]=1234&display=full"
Aktualizacja statusu zamówienia
Utwórz nowy rekord order_history — to uruchamia zmianę statusu i wysyła e-mail do klienta:
curl -u "KEY:" -X POST -H "Content-Type: application/xml" \
-d '<prestashop><order_history>
<id_order>1234</id_order>
<id_order_state>4</id_order_state>
</order_history></prestashop>' "https://your-store.com/api/order_histories"
Domyślne ID statusów: 1=Oczekiwanie na płatność, 2=Płatność zaakceptowana, 3=W realizacji, 4=Wysłane, 5=Dostarczone, 6=Anulowane, 7=Zwrócone. Mogą się różnić w zależności od instalacji — sprawdź order_states dla listy właściwej dla Twojego sklepu.
Numery śledzenia: Pobierz rekord order_carriers dla zamówienia metodą GET, dodaj tracking_number, wyślij z powrotem metodą PUT.
Tworzenie zamówień przez API jest technicznie możliwe, ale niezalecane. Tworzenie zamówienia obejmuje walidację koszyka, obliczanie podatków, przetwarzanie płatności, odejmowanie stanu magazynowego i wykonywanie hooków — API pomija większość z tego. Przy importach z marketplace utwórz koszyk przez API i przetwórz go przez dedykowany front controller.
Biblioteka klienta PHP
composer require prestashop/prestashop-webservice-lib
Lub pobierz pojedynczy plik z GitHub.
$ws = new PrestaShopWebservice('https://your-store.com', 'API_KEY', false);
// List products
$xml = $ws->get(['resource' => 'products', 'display' => 'full', 'limit' => 10]);
foreach ($xml->products->product as $p) {
echo $p->id . ' - ' . $p->name->language . "\n";
}
// Create product from blank schema
$blank = $ws->get(['url' => 'https://your-store.com/api/products?schema=blank']);
$blank->product->active = 1;
$blank->product->price = 29.99;
$blank->product->name->language[0] = 'New Product';
$blank->product->name->language[0]['id'] = 1;
$blank->product->link_rewrite->language[0] = 'new-product';
$blank->product->link_rewrite->language[0]['id'] = 1;
$blank->product->id_category_default = 2;
$result = $ws->add(['resource' => 'products', 'postXml' => $blank->asXML()]);
// Update stock
function updateStock($ws, int $pid, int $qty, int $combo = 0): void {
$xml = $ws->get([
'resource' => 'stock_availables',
'filter[id_product]' => $pid,
'filter[id_product_attribute]' => $combo,
'display' => 'full'
]);
$sid = (int)$xml->stock_availables->stock_available->id;
$sxml = $ws->get(['resource' => 'stock_availables', 'id' => $sid]);
$sxml->stock_available->quantity = $qty;
$ws->edit(['resource' => 'stock_availables', 'id' => $sid, 'putXml' => $sxml->asXML()]);
}
// Export orders since date
$xml = $ws->get([
'resource' => 'orders',
'display' => '[id,reference,total_paid,current_state,date_add]',
'filter[date_add]' => '[2025-06-01,9999-12-31]',
'sort' => '[date_add_DESC]', 'limit' => 500
]);
Rozszerzanie starszego Webservice z modułu
Jeśli moduł posiada dane potrzebne ERP, PIM albo narzędziu raportowemu, udostępnij niestandardowy zasób Webservice zamiast pozwalać zewnętrznemu systemowi czytać tabele modułu bezpośrednio. PrestaShop dokumentuje to przez hook addWebserviceResources.
public function hookAddWebserviceResources($params)
{
return [
'articles' => [
'description' => 'Blog articles',
'class' => 'Article',
'forbidden_method' => ['DELETE'],
],
];
}ObjectModel nadal kontroluje kształt danych przez $webserviceParameters. Ograniczaj udostępnione pola, blokuj destrukcyjne metody, gdy nie są potrzebne, i testuj ?schema=synopsis dla własnego zasobu tak samo jak dla zasobu natywnego.
Wzorce integracji
Integracja z ERP
Najczęstszy scenariusz. Produkty, ceny i stany magazynowe płyną z ERP do PrestaShop; zamówienia i dane klientów wracają w drugą stronę. Dobre praktyki: używaj kodów referencyjnych (SKU/EAN) jako wspólnych identyfikatorów, planuj synchronizację stanów co 15 minut, a produktów co godzinę, śledź znacznik czasu ostatniej synchronizacji za pomocą filter[date_upd], z góry ustal zasady rozwiązywania konfliktów (zwykle wygrywa ERP) i loguj wszystko.
Magazyn i POS
WMS działa w cyklu: przyjęcie towaru → aktualizacja stanu przez API; odpytywanie zamówień → wysyłka → aktualizacja śledzenia przesyłki przez API. Integracja POS jest podobna — stany muszą się synchronizować niemal w czasie rzeczywistym, aby zakupy w sklepie stacjonarnym natychmiast zmniejszały dostępność online.
Synchronizacja z marketplace
Integracje z Allegro, Amazon, eBay wymagają eksportu produktów z obrazami, importu zamówień (przez koszyk + niestandardowe przetwarzanie zamiast bezpośredniego POST zamówienia) oraz dwukierunkowej synchronizacji stanów magazynowych, aby zapobiec nadsprzedaży.
Księgowość
Tryb tylko do odczytu: pobieraj zamówienia, faktury i korekty według dziennego/tygodniowego harmonogramu. Wymaga jedynie uprawnień GET.
Zmiany API w PrestaShop 9
Starszy Webservice nadal działa w PS 9 — nie został oznaczony jako przestarzały. Istniejące integracje działają po aktualizacji.
AdminAPI — Nowe API oparte na Symfony
PS 9 wprowadza nowe AdminAPI obok starego Webservice. Kluczowe różnice:
- Uwierzytelnianie: OAuth2 z client credentials (zamiast Basic Auth z kluczem API)
- Format: Wyłącznie JSON (zamiast domyślnego XML)
- Architektura: Symfony / API Platform z dokumentacją OpenAPI/Swagger pod
/admin-api/docs - Pokrycie: Rosnące — nie obejmuje jeszcze wszystkich zasobów starego Webservice
# Get OAuth2 token
curl -X POST https://your-store.com/admin-api/access_token \
-d "grant_type=client_credentials&client_id=ID&client_secret=SECRET"
# Use bearer token
curl -H "Authorization: Bearer eyJ0eXAi..." https://your-store.com/admin-api/products
Tokeny wygasą (domyślnie: 1 godzina) — obsłuż odświeżanie w swojej integracji. Zakresy (product_read, product_write, order_read) kontrolują dostęp w sposób granularny. Tworzenie klientów API: Zaawansowane > AdminAPI.
Używaj AdminAPI do nowych integracji z PS 9+. Używaj starego Webservice dla szerokiego pokrycia zasobów lub wstecznej kompatybilności z PS 1.6/1.7/8.x. Możesz używać obu w tej samej integracji.
Typowe problemy
401 Unauthorized: Zły klucz (sprawdź białe znaki), klucz wyłączony, Webservice wyłączony lub klucz wysłany jako parametr URL zamiast nagłówka Basic Auth.
403 Forbidden: Klucz nie ma uprawnień do zasobu lub metody HTTP. Sprawdź macierz uprawnień.
404 Not Found: Zasób nie istnieje lub przepisywanie URL jest uszkodzone. Test: curl -u "KEY:" "https://store.com/webservice/dispatcher.php?url=products" — jeśli to działa, ale /api/products nie, napraw reguły przepisywania.
Błędy parsowania XML: Używaj CDATA dla znaków specjalnych (<![CDATA[HTML & more]]>), zawsze opakowuj w element główny <prestashop>, wysyłaj UTF-8 z właściwym nagłówkiem Content-Type.
Wolne operacje masowe: API przetwarza jedno żądanie naraz. Przy 10 000+ elementów:
- Żądaj tylko potrzebnych pól za pomocą
display— unikajdisplay=fullna dużych katalogach - Filtruj po
date_upd, aby synchronizować tylko zmienione rekordy - Używaj ponownie uchwytów curl dla połączeń trwałych
- Przy początkowych importach 50K+ produktów rozważ bezpośredni dostęp do bazy z czyszczeniem cache
// Efficient bulk stock update — reuse handle
$ch = curl_init();
curl_setopt($ch, CURLOPT_USERPWD, "$apiKey:");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/xml']);
foreach ($updates as $stockId => $qty) {
curl_setopt($ch, CURLOPT_URL, "$url/api/stock_availables/$stockId");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($ch, CURLOPT_POSTFIELDS,
"<prestashop><stock_available><id>$stockId</id><quantity>$qty</quantity></stock_available></prestashop>");
curl_exec($ch);
}
curl_close($ch);
Najlepsze praktyki bezpieczeństwa
- Jeden klucz na integrację — możesz odwołać jeden bez wpływu na pozostałe
- Minimalne uprawnienia — synchronizacja stanów nie potrzebuje DELETE na produktach
- Zawsze HTTPS — klucze w czystym HTTP są widoczne dla podsuchujących sieć
- Biała lista IP — najskuteczniejszy pojedynczy środek dla integracji serwer-serwer
- Rotacja kluczy — co 6-12 miesięcy
- Zmienne środowiskowe — nigdy nie commituj kluczy do repozytorium
- Limitowanie zapytań — API nie ma wbudowanego limitu; dodaj go na poziomie serwera WWW
# Nginx rate limiting
limit_req_zone $binary_remote_addr zone=api:10m rate=30r/s;
location /api/ {
limit_req zone=api burst=50 nodelay;
try_files $uri $uri/ /webservice/dispatcher.php?$args;
}
Logowanie audytowe: PrestaShop nie ma wbudowanego logowania API. Parsuj logi dostępu serwera WWW pod kątem zapytań do /api/ lub nadpisz WebserviceRequest, aby logować znacznik czasu, IP, zasób, metodę i kod odpowiedzi. Niezbędne dla zgodności z GDPR/PCI, gdy uzyskiwany jest dostęp do danych klientów.
Alternatywy dla Webservice
Bezpośredni dostęp do bazy danych
Rzędy wielkości szybszy przy operacjach masowych, ale pomija walidację, hooki i inwalidację cache. Odpowiedni do jednorazowych importów, raportów tylko do odczytu i napraw awaryjnych. Nieodpowiedni do bieżącej synchronizacji ani do operacji dotyczących zamówień czy płatności. Po zmianach bezpośrednio w bazie zawsze czyść cache.
Hooki modułowe do synchronizacji w czasie rzeczywistym
Zamiast odpytywać API, wysyłaj dane przez hooki w momencie wystąpienia zdarzeń:
public function hookActionProductUpdate($params) {
$product = $params['product'];
$payload = json_encode([
'id' => $product->id, 'reference' => $product->reference,
'price' => $product->price,
'quantity' => StockAvailable::getQuantityAvailableByProduct($product->id),
]);
$ch = curl_init('https://erp.example.com/webhook/product-update');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_exec($ch); curl_close($ch);
}
Niestandardowe endpointy modułowe
Dla operacji, z którymi Webservice radzi sobie słabo, zbuduj własne API jako front controller modułu. Pełna kontrola nad formatem, uwierzytelnianiem i logiką biznesową — przetwarzaj operacje masowe w jednym żądaniu, korzystając z natywnych klas PrestaShop do walidacji.
Wybór właściwego podejścia
| Scenariusz | Najlepsze podejście |
|---|---|
| Standardowa integracja ERP/WMS | Webservice API |
| Nowa integracja z PS 9+ | AdminAPI (OAuth2, JSON) |
| Import masowy 50K+ produktów | Bezpośrednia baza + czyszczenie cache |
| Synchronizacja zdarzeń w czasie rzeczywistym | Hooki modułowe (webhook push) |
| Niestandardowa logika biznesowa | Niestandardowy endpoint modułu |
| Raporty tylko do odczytu | Bezpośrednie zapytania do bazy |
PrestaShop Webservice jest stabilne od ponad dekady. Dla PS 9+ AdminAPI oferuje nowoczesną alternatywę. Wybierz odpowiednie narzędzie do każdego zadania, wdrażaj z uwzględnieniem bezpieczeństwa i obsługi błędów od pierwszego dnia i zawsze testuj na konkretnej wersji PrestaShop, na którą celujesz.
Powiązane: Smart Google Merchant Feed Manager · Hooki i override’y · Analityka dla sklepów internetowych (blog)