Programiści

API 4pricing dla programistów

Połącz własny system (CRM, ERP, sklep internetowy) z 4pricing i odpytuj ceny konkurencji, grupy porównawcze oraz alerty bezpośrednio z poziomu swojego kodu.

Bazowy adres URL: https://4pricing.net/api/v1/pricing · Specyfikacja OpenAPI (JSON)

Szybka integracja w 3 krokach

To najkrótsza droga, by zobaczyć dane z 4pricing na własnej stronie. Skopiujesz jeden plik, wkleisz do niego swój klucz i wgrasz go na hosting — bez frameworka, bez instalacji.

Czego potrzebujesz
  • Aktywnej subskrypcji 4pricing (API jest wliczone w każdy plan).
  • Hostingu z PHP — ma go prawie każdy zwykły hosting (cPanel, Plesk i podobne).
  • Sposobu na wgranie pliku: menedżera plików u dostawcy hostingu lub programu FTP.
  1. Krok 1: Utwórz swój klucz API

    Zaloguj się na panel.4pricing.net i otwórz Monitoring cen → API i klucze.

    Kliknij „Wygeneruj klucz”, nadaj mu nazwę (na przykład „mój sklep”) i skopiuj klucz zaczynający się od prc_live_. Wyświetla się tylko raz — jeśli go zgubisz, utwórz nowy, a stary unieważnij.

    Otwórz API i klucze w panelu →

  2. Krok 2: Skopiuj gotowy plik i wklej swój klucz

    Skopiuj poniższy plik PHP do edytora tekstu (Notatnik, TextEdit lub VS Code) i zapisz go pod nazwą 4pricing-prices.php.

    php4pricing-prices.php
    <?php
    // =====================================================================
    // WKLEJ TUTAJ SWÓJ KLUCZ API (panel.4pricing.net → API i klucze), między cudzysłowami
    $apiKey = 'WKLEJ_TUTAJ_KLUCZ';
    // =====================================================================
    
    header('Content-Type: text/html; charset=utf-8');
    
    function h($text) { return htmlspecialchars((string) $text, ENT_QUOTES, 'UTF-8'); }
    function money($cents) {
        if ($cents === null) { return '—'; }
        return number_format($cents / 100, 2, ',', ' ');
    }
    
    if (strpos($apiKey, 'prc_') !== 0) {
        exit('<p>' . h('Brakuje klucza API: otwórz plik i wklej swój klucz w zaznaczonym wierszu.') . '</p>');
    }
    
    $ch = curl_init('https://4pricing.net/api/v1/pricing/groups/');
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_USERAGENT => 'my-shop-integration/1.0',
        CURLOPT_TIMEOUT => 30,
        CURLOPT_HTTPHEADER => ['X-API-Key: ' . $apiKey, 'Accept: application/json'],
    ]);
    $body = curl_exec($ch);
    $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    
    if ($body === false) {
        exit('<p>' . h('Nie udało się połączyć z 4pricing:' . ' ' . curl_error($ch)) . '</p>');
    }
    if ($status !== 200) {
        $hints = [401 => 'klucz API jest błędny lub został unieważniony', 402 => 'konto nie ma aktywnej subskrypcji 4pricing (albo brakuje kredytów)', 429 => 'zbyt wiele zapytań w ciągu minuty, spróbuj ponownie za minutę'];
        $hint = isset($hints[$status]) ? ' — ' . $hints[$status] : '';
        exit('<p>' . h('4pricing odpowiedział błędem' . ' ' . $status . $hint) . '</p><pre>' . h($body) . '</pre>');
    }
    
    $groups = json_decode($body, true);
    $verdicts = [
        'cheapest' => 'Jesteś najtańszy',
        'too_cheap' => 'Dużo taniej niż rynek — możesz podnieść cenę',
        'competitive' => 'Konkurencyjna cena',
        'too_expensive' => 'Drożej niż większość konkurentów',
        'no_competitors' => 'Brak jeszcze ceny konkurencji',
        'no_own_price' => 'Brakuje Twojej ceny',
    ];
    
    echo '<!doctype html><html><head><meta charset="utf-8"><title>' . h('Moje monitorowane produkty') . '</title>';
    echo '<style>body{font-family:Arial,sans-serif;margin:24px}table{border-collapse:collapse}';
    echo 'th,td{border:1px solid #ddd;padding:6px 10px;text-align:left}th{background:#f5f5f5}</style>';
    echo '</head><body><h1>' . h('Moje monitorowane produkty') . '</h1>';
    
    if (!$groups) {
        echo '<p>' . h('Nie masz jeszcze żadnych porównywanych produktów.') . '</p>';
    } else {
        echo '<table><tr><th>' . h('Produkt') . '</th><th>' . h('SKU') . '</th>';
        echo '<th>' . h('Twoja cena') . '</th><th>' . h('Najtańsza konkurencja') . '</th>';
        echo '<th>' . h('Różnica') . '</th><th>' . h('Werdykt') . '</th></tr>';
        foreach ($groups as $g) {
            $yours = $g['own_price_cents_effective'];
            $cheapest = $g['min_competitor_cents'];
            $diff = '—';
            if ($yours !== null && $cheapest !== null) {
                $diff = ($yours > $cheapest ? '+' : '') . money($yours - $cheapest);
            }
            $verdict = isset($verdicts[$g['verdict']]) ? $verdicts[$g['verdict']] : $g['verdict'];
            echo '<tr><td>' . h($g['name']) . '</td><td>' . h($g['sku']) . '</td>';
            echo '<td>' . money($yours) . '</td><td>' . money($cheapest) . '</td>';
            echo '<td>' . $diff . '</td><td>' . h($verdict) . '</td></tr>';
        }
        echo '</table>';
    }
    echo '</body></html>';
    
    Zastąp WKLEJ_TUTAJ_KLUCZ swoim kluczem, zachowując cudzysłowy wokół niego. To jedyny wiersz, który musisz zmienić.
  3. Krok 3: Wgraj plik na stronę i otwórz go w przeglądarce

    Wgraj 4pricing-prices.php na swoją stronę za pomocą menedżera plików lub FTP, do tego samego folderu co strona (zwykle public_html).

    Otwórz w przeglądarce https://twoja-strona/4pricing-prices.php. Zobaczysz tabelę z każdym porównywanym produktem: Twoja cena, najniższa cena konkurencji, różnica i werdykt.

Plik: lista Twoich produktów z najniższą ceną konkurencji

Plik pobiera z 4pricing Twoje porównywane produkty (GET /groups/) i pokazuje je w tabeli. Odczyt danych jest bezpłatny i nie zużywa kredytów.

  • „Twoja cena” to cena, którą 4pricing zna dla Ciebie; „Najtańsza konkurencja” to najniższa cena znaleziona u konkurentów, których monitorujesz.
  • Ceny są pokazane w pełnych jednostkach (12999 groszy to 129,99); kreska (—) oznacza, że 4pricing nie ma jeszcze ceny, a nie że cena wynosi zero.
  • Jeśli zamiast tabeli widzisz błąd, komunikat podpowiada, co poprawić: błędny klucz, nieaktywna subskrypcja albo zbyt wiele zapytań w ciągu minuty.

Drugi przepis: wyślij swoją cenę

Użyj go, gdy 4pricing ma poznać Twoją cenę bez odczytywania jej ze strony sklepu — na przykład prosto z bazy danych sklepu. Wysyłanie własnych cen jest bezpłatne (bez kredytów) i nie wlicza się do limitu monitorowanych adresów URL w Twoim planie.

PoleZnaczenie
skuTwój kod produktu; 4pricing po nim znajduje produkt albo tworzy go przy pierwszym wysłaniu
namenazwa produktu, taka, jaką chcesz widzieć w 4pricing
urlopcjonalnie: adres strony produktu w Twoim sklepie (nigdy nie jest odczytywany)
price_centscena pomnożona przez 100, bez ułamków: 49,99 → 4999
currencykod waluty, na przykład EUR, GBP lub RON (RON, jeśli go brakuje)
php4pricing-send-price.php
<?php
// =====================================================================
// WKLEJ TUTAJ SWÓJ KLUCZ API (panel.4pricing.net → API i klucze), między cudzysłowami
$apiKey = 'WKLEJ_TUTAJ_KLUCZ';
// =====================================================================

// TWOJE PRODUKTY: jeden blok na produkt. price_cents = cena x 100 (49,99 daje 4999).
$products = [
    [
        'sku' => 'BIALA-KOSZULKA-M',
        'name' => 'Biała koszulka, rozmiar M',
        'url' => 'https://twoj-sklep.example/biala-koszulka-m',
        'price_cents' => 4999,
        'currency' => 'EUR',
    ],
];

header('Content-Type: text/html; charset=utf-8');

function h($text) { return htmlspecialchars((string) $text, ENT_QUOTES, 'UTF-8'); }

if (strpos($apiKey, 'prc_') !== 0) {
    exit('<p>' . h('Brakuje klucza API: otwórz plik i wklej swój klucz w zaznaczonym wierszu.') . '</p>');
}

$ch = curl_init('https://4pricing.net/api/v1/pricing/own-products/bulk');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_USERAGENT => 'my-shop-integration/1.0',
    CURLOPT_TIMEOUT => 60,
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => ['X-API-Key: ' . $apiKey, 'Content-Type: application/json', 'Accept: application/json'],
    CURLOPT_POSTFIELDS => json_encode(['items' => $products], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);

if ($body === false) {
    exit('<p>' . h('Nie udało się połączyć z 4pricing:' . ' ' . curl_error($ch)) . '</p>');
}
if ($status !== 200) {
    $hints = [401 => 'klucz API jest błędny lub został unieważniony', 402 => 'konto nie ma aktywnej subskrypcji 4pricing (albo brakuje kredytów)', 429 => 'zbyt wiele zapytań w ciągu minuty, spróbuj ponownie za minutę'];
    $hint = isset($hints[$status]) ? ' — ' . $hints[$status] : '';
    exit('<p>' . h('4pricing odpowiedział błędem' . ' ' . $status . $hint) . '</p><pre>' . h($body) . '</pre>');
}

$result = json_decode($body, true);
echo '<h1>' . h('Ceny wysłane do 4pricing') . '</h1>';
echo '<p>' . h('Utworzone nowe produkty:') . ' ' . (int) $result['created'] . '</p>';
echo '<p>' . h('Zaktualizowane produkty:') . ' ' . (int) $result['updated'] . '</p>';
if (!empty($result['errors'])) {
    echo '<p>' . h('Wiersze z problemami:') . '</p><ul>';
    foreach ($result['errors'] as $error) {
        echo '<li>' . h($error) . '</li>';
    }
    echo '</ul>';
}
  • Zapisz go jako 4pricing-send-price.php, wklej swój klucz, uzupełnij wiersze z produktami, wgraj plik i otwórz go jednorazowo: strona pokaże, ile produktów zostało utworzonych, a ile zaktualizowanych.
  • Jedno zapytanie może zawierać do 2000 produktów; błędny wiersz zostanie zgłoszony, a pozostałe i tak się zapiszą. Ponowne wysłanie tego samego sku aktualizuje cenę.

Te same wywołania w curl

Jeśli wolisz terminal, te dwa polecenia robią dokładnie to samo co dwa pliki PHP:

bash
curl https://4pricing.net/api/v1/pricing/groups/ \
  -H "X-API-Key: WKLEJ_TUTAJ_KLUCZ"
bash
curl -X POST https://4pricing.net/api/v1/pricing/own-products/bulk \
  -H "X-API-Key: WKLEJ_TUTAJ_KLUCZ" \
  -H "Content-Type: application/json" \
  -d '{"items":[{"sku":"BIALA-KOSZULKA-M","name":"Biała koszulka, rozmiar M","url":"https://twoj-sklep.example/biala-koszulka-m","price_cents":4999,"currency":"EUR"}]}'
Zadbaj o bezpieczeństwo klucza
  • Klucz daje dostęp do całego Twojego konta 4pricing. Trzymaj go wyłącznie w plikach po stronie serwera (PHP, Twój backend) — nigdy w JavaScripcie w przeglądarce ani w publicznym repozytorium.
  • Każdy, kto zna adres wgranej strony, zobaczy tabelę z cenami (klucza nie zobaczy). Nadaj plikowi nazwę trudną do odgadnięcia, zabezpiecz folder hasłem albo usuń plik, gdy już go nie potrzebujesz.
  • Jeśli klucz wycieknie, unieważnij go w API i klucze — przestaje działać natychmiast — i utwórz nowy.

Uwierzytelnianie

  • Każde zapytanie przekazuje Twój klucz w nagłówku X-API-Key. Działa też Authorization: Bearer prc_live_… (tylko dla kluczy zaczynających się od prc_).
  • Nie ma zakresów uprawnień: klucz może odczytywać i zmieniać wszystko na Twoim koncie 4pricing. Utwórz osobny klucz dla każdej integracji (sklep, ERP, raport), aby móc unieważnić jeden bez zatrzymywania pozostałych.
  • Brakujący, błędny lub unieważniony klucz kończy się odpowiedzią 401. Unieważnienie działa natychmiast. Zbyt wiele nieprawidłowych kluczy w ciągu minuty kończy się odpowiedzią 429.
  • Klucze tworzy się, przegląda i unieważnia wyłącznie w panelu (Monitoring cen → API i klucze); samo API nie zarządza kluczami. Utworzenie klucza wymaga aktywnej subskrypcji 4pricing.
http
X-API-Key: prc_live_…
# or
Authorization: Bearer prc_live_…

Bazowy adres URL i konwencje

  • Każda ścieżka w tej dokumentacji jest względna wobec bazowego adresu URL — /groups/ oznacza https://4pricing.net/api/v1/pricing/groups/.
  • Zapytania i odpowiedzi mają format JSON (Content-Type: application/json).
  • Kwoty to liczby całkowite w najmniejszych jednostkach waluty (groszach, centach): price_cents = 12999 oznacza 129,99. Wartości procentowe podawane są w punktach bazowych (100 = 1%).
  • Nieznana wartość to null, nigdy 0 — pokaż ją jako „—”.
  • Kolekcje wywołuje się z ukośnikiem na końcu (/products/, /groups/, /insights/).
  • Listy podzielone na strony zwracają łączną liczbę w nagłówku X-Total-Count (na przykład GET /products/?skip=0&limit=200).
  • Wysyłaj nagłówek User-Agent z nazwą Twojej integracji (na przykład my-shop-integration/1.0). Zapora przed API odpowiada kodem 403 na niektóre ogólne ustawienia domyślne bibliotek, takie jak Python-urllib.

Limit zapytań, subskrypcja i limity planu

Limit zapytań

  • 60 zapytań na minutę na KONTO, w oknie przesuwnym — wszystkie klucze tego samego konta dzielą te same 60.
  • Każda odpowiedź zawiera X-RateLimit-Limit, X-RateLimit-Remaining i X-RateLimit-Reset (długość okna, w sekundach).
  • Po przekroczeniu limitu dostajesz 429 z nagłówkiem Retry-After (w sekundach). Poczekaj tyle czasu i ponów zapytanie — poniższe przykłady robią to za Ciebie.
http
HTTP/2 200
x-ratelimit-limit: 60
x-ratelimit-remaining: 59
x-ratelimit-reset: 60

HTTP/2 429
retry-after: 60
{"detail":"Rate limit exceeded"}

Subskrypcja i limity planu

  • API wymaga aktywnej subskrypcji 4pricing; bez niej każde zapytanie kończy się kodem 402 z kodem błędu plan_required.
  • Każdy plan zawiera API z tymi samymi limitami co panel. Przekroczenie limitu przy dodawaniu lub ponownym włączaniu czegoś kończy się kodem 402 z kodem błędu plan_limit i komunikatem, którego limitu dotyczy.
LimitZnaczenie
Monitorowane adresy URLKażdy adres strony produktu, który 4pricing odczytuje, liczy się osobno: Twoja własna strona i każda strona konkurenta. Ceny wysyłane przez /own-products nie są wliczane.
Sklepy konkurencjiLiczba różnych witryn konkurencji (domen), które monitorujesz.
Minimalny odstęp między sprawdzeniamiJak często ten sam adres URL może być sprawdzany. Krótsze odstępy są automatycznie podnoszone do minimum Twojego planu; zbyt wczesne odświeżenie adresu URL kończy się kodem 402 plan_limit.

Które wywołania zużywają kredyty

Odczyt strony sklepu kosztuje kredyty z portfela Twojego konta. Poniższe wywołania sprawdzają saldo PRZED odczytem czegokolwiek: jeśli nie wystarcza, dostajesz 402 insufficient_credits, a jeśli portfela nie można teraz odczytać, dostajesz 503 credit_wallet_unavailable (spróbuj później). W obu przypadkach nic nie jest odczytywane i nic nie jest pobierane.

Wywołania zużywające kredyty

MetodaEndpointCo robiKoszt
POST/groups/{group_id}/membersDodaj adres URL do grupy, przez product_id lub z nowego adresu (nowy adres jest odczytywany od razu)Kredyty
POST/groups/{group_id}/refreshSprawdź teraz każdy adres URL w grupieKredyty
POST/groups/{group_id}/suggestions„Znajdź konkurentów”: proponowane adresy URL konkurentów z oceną i uzasadnieniemKredyty
POST/products/Zacznij monitorować adres URL (url, name, rola own lub competitor) — jest odczytywany od razuKredyty
POST/products/{product_id}/refreshSprawdź teraz cenę pod tym adresem URL (z poszanowaniem minimalnego odstępu Twojego planu)Kredyty
POST/search/Wyszukaj aktualną cenę produktu u sprzedawców (kredyty za każdego przeszukanego sprzedawcę)Kredyty

Wywołania bezpłatne

  • Każdy odczyt (GET): produkty, grupy, porównania, historia, alerty, wnioski, podsumowania dnia, kredyty, statystyki.
  • POST /own-products/ i POST /own-products/bulk — Twoje własne ceny.
  • POST /sales/bulk — Twoja sprzedaż.
  • Alerty, ustawienia, potwierdzenia i wszystko inne, co nie odczytuje strony sklepu.
  • Zaplanowane monitorowanie śledzonych adresów URL także zużywa kredyty, przy każdym sprawdzeniu; GET /credits/ pokazuje Twoje saldo i prognozę.
  • POST /products/import dodaje wiele adresów URL naraz bez natychmiastowego odczytu: są one sprawdzane — i rozliczane — przez zaplanowane monitorowanie.

Opis endpointów

Wszystkie operacje dostępne dla klucza, pogrupowane według przeznaczenia. Specyfikacja OpenAPI opisuje każdą z nich pole po polu, wraz z dokładną treścią zapytania i odpowiedzi.

Twoje własne ceny

Podaj 4pricing swoją cenę bezpośrednio, bez odczytywania strony sklepu. Bezpłatnie.

MetodaEndpointCo robiKoszt
POST/own-products/Wyślij swoją aktualną cenę jednego produktu (wyszukiwanego po sku, a w razie braku po nazwie; tworzony, jeśli nie istnieje)Bezpłatnie
POST/own-products/bulkWyślij swoje ceny do 2000 produktów w jednym zapytaniu; błędne wiersze są zgłaszane, reszta zostaje zapisanaBezpłatnie

Porównywane produkty (grupy)

Grupa to jeden Twój produkt razem ze stronami konkurentów, którzy sprzedają to samo. Przechowuje werdykt i rekomendowaną cenę.

MetodaEndpointCo robiKoszt
GET/groups/Wszystkie porównywane produkty, każdy z Twoją ceną, najniższą ceną konkurencji, werdyktem i rekomendowaną cenąBezpłatnie
POST/groups/Utwórz porównywany produkt (nazwa, sku, Twoja cena, koszt, strategia cenowa)Bezpłatnie
GET/groups/{group_id}Jeden porównywany produktBezpłatnie
PUT/groups/{group_id}Zaktualizuj cenę, koszt, strategię, odstęp sprawdzeń lub powiązanie ze sklepem (store_kind)Bezpłatnie
DELETE/groups/{group_id}Usuń grupę; jej adresy URL pozostają monitorowaneBezpłatnie
GET/groups/{group_id}/comparisonTwoja pozycja wobec każdego konkurenta, z rekomendowaną ceną i sposobem jej obliczeniaBezpłatnie
GET/groups/{group_id}/historyHistoria cen każdego adresu URL w grupieBezpłatnie
GET/groups/seriesTwoja pozycja na rynku, dzień po dniu, dla wszystkich produktówBezpłatnie
POST/groups/{group_id}/membersDodaj adres URL do grupy, przez product_id lub z nowego adresu (nowy adres jest odczytywany od razu)Kredyty
DELETE/groups/{group_id}/members/{product_id}Usuń adres URL z grupy (pozostaje monitorowany)Bezpłatnie
POST/groups/{group_id}/refreshSprawdź teraz każdy adres URL w grupieKredyty
POST/groups/{group_id}/apply-recommendedUstaw rekomendowaną cenę jako swoją cenę w 4pricing (wyślij cenę widzianą wcześniej; 409, jeśli się zmieniła)Bezpłatnie
GET/groups/suggestions/sourcesŹródła dostępne dla funkcji „Znajdź konkurentów”Bezpłatnie
POST/groups/{group_id}/suggestions„Znajdź konkurentów”: proponowane adresy URL konkurentów z oceną i uzasadnieniemKredyty

Monitorowane adresy URL

Jeden wiersz na adres strony odczytywany przez 4pricing, Twój lub konkurenta (rola own lub competitor).

MetodaEndpointCo robiKoszt
GET/products/Monitorowane adresy URL, podzielone na strony (skip, limit do 500; łączna liczba w X-Total-Count)Bezpłatnie
POST/products/Zacznij monitorować adres URL (url, name, rola own lub competitor) — jest odczytywany od razuKredyty
POST/products/importDodaj wiele adresów URL naraz; zostaną odczytane później przez zaplanowane monitorowanieBezpłatnie
GET/products/exportEksport aktywnych adresów URL do CSVBezpłatnie
GET/products/{product_id}Jeden monitorowany adres URL z ostatnią cenąBezpłatnie
PATCH/products/{product_id}Zmień nazwę, kategorię lub odstęp między sprawdzeniamiBezpłatnie
DELETE/products/{product_id}Przestań monitorować adres URL (pozostaje jako nieaktywny)Bezpłatnie
POST/products/{product_id}/refreshSprawdź teraz cenę pod tym adresem URL (z poszanowaniem minimalnego odstępu Twojego planu)Kredyty
GET/products/{product_id}/historyHistoria cen jednego adresu URLBezpłatnie
GET/products/sparklinesKrótka historia cen dla kilku adresów URL narazBezpłatnie
GET/products/price-changesAdresy URL, których cena zmieniła się przy ostatnim sprawdzeniuBezpłatnie

Sprawdź cenę produktu u sprzedawców od razu.

MetodaEndpointCo robiKoszt
POST/search/Wyszukaj aktualną cenę produktu u sprzedawców (kredyty za każdego przeszukanego sprzedawcę)Kredyty

Alerty

Reguły cenowe i skrzynka alertów, które się uruchomiły.

MetodaEndpointCo robiKoszt
GET/alerts/Twoje alerty cenoweBezpłatnie
POST/alerts/Utwórz alert (cena poniżej/powyżej, spadek w %, ponowna dostępność, podcięcie przez konkurenta…)Bezpłatnie
DELETE/alerts/{alert_id}Usuń alertBezpłatnie
POST/alerts/{alert_id}/rearmUzbrój ponownie alert, który się uruchomiłBezpłatnie
GET/alerts/eventsSkrzynka alertów, które się uruchomiłyBezpłatnie
GET/alerts/events/unread-countIle masz nieprzeczytanych alertówBezpłatnie
POST/alerts/events/read-allOznacz alerty jako przeczytane (opcjonalnie tylko te sprzed wskazanego momentu)Bezpłatnie
POST/alerts/events/{event_id}/readOznacz jeden alert jako przeczytanyBezpłatnie

Kredyty

Saldo, prognoza i każdy ruch kredytów.

MetodaEndpointCo robiKoszt
GET/credits/Saldo kredytów i prognoza zużyciaBezpłatnie
GET/credits/ledgerKażdy ruch kredytówBezpłatnie
GET/credits/by-productKredyty zużyte na adres URL (łącznie i w ostatnich 30 dniach)Bezpłatnie

Twoja sprzedaż

Dzienna sprzedaż na produkt, służąca do obliczania wartości każdej okazji. Bezpłatnie.

MetodaEndpointCo robiKoszt
POST/sales/bulkDzienna sprzedaż na produkt (sku lub group_id, day, units_sold, revenue_cents; opcjonalnie stock_units, cost_cents), do 2000 wierszy; ponowne wysłanie tego samego produktu i dnia nadpisuje wpisBezpłatnie

Wnioski, okazje i podsumowania dnia

Co się zmieniło, dlaczego to ważne i co zrobić — oraz dzienne podsumowanie.

MetodaEndpointCo robiKoszt
GET/insights/Wnioski z dowodami i propozycjami cen (X-Total-Count)Bezpłatnie
GET/insights/{insight_id}Jeden wniosek ze szczegółamiBezpłatnie
POST/insights/{insight_id}/dismissOdrzuć wniosekBezpłatnie
GET/opportunities/Podsumowanie okazji: wartość wyliczona z Twojej sprzedaży, oddzielona od szacunku rynkowegoBezpłatnie
GET/briefings/Historia dziennych podsumowańBezpłatnie
GET/briefings/latestOstatnie dzienne podsumowanieBezpłatnie
POST/briefings/generateZbuduj ponownie dzisiejsze podsumowanie z otwartych wniosków (nic nie wysyła)Bezpłatnie

Akcje cenowe

Zmiany cen, które zostały zaproponowane, wysłane, zastosowane lub cofnięte. Przez API możesz je odczytywać i potwierdzać te otrzymane przez webhook.

MetodaEndpointCo robiKoszt
GET/actions/Akcje cenowe: zaproponowane, wysłane, zastosowane, cofnięteBezpłatnie
POST/actions/{action_id}/confirmPotwierdź, że Twój system zastosował cenę otrzymaną przez price.apply lub price.revertBezpłatnie

Ustawienia

Ustawienia konta, w tym adres i sekret webhooka.

MetodaEndpointCo robiKoszt
GET/settings/Ustawienia konta (sprzedawcy, strategia repricingu, dostarczanie alertów, webhook)Bezpłatnie
PUT/settings/Zmień ustawienia, w tym alert_webhook_url, alert_webhook_secret i alert_webhook_enabledBezpłatnie

Statystyki

Przegląd konta i kondycja sprawdzeń cen.

MetodaEndpointCo robiKoszt
GET/stats/Statystyki konta: adresy URL, alerty, zmiany z 24 godzin, grupyBezpłatnie
GET/stats/scrapersKondycja sprawdzeń cen w podziale na sprzedawcówBezpłatnie

53 endpoints · https://4pricing.net/api/v1/pricing/openapi.json

Czego API nie potrafi

Niektóre rzeczy celowo zostają w panelu, gdzie decyduje zalogowana osoba. Przez API te ścieżki odpowiadają kodem 404:

ŚcieżkaDlaczego
/keys/…Tworzenie i unieważnianie kluczy — klucz nie może tworzyć kolejnych kluczy.
/autopilot/…Polityka autopilota, która decyduje, co może się zmienić bez udziału człowieka; wyciekły klucz nie może jej rozszerzyć.
/watchlists/…Listy obserwowanych, które zużywają kredyty przy każdym uruchomieniu.
/actions/{action_id}/approve · reject · revertZatwierdzenie, odrzucenie lub cofnięcie zmiany ceny to decyzja, którą człowiek podejmuje w panelu. API może tylko odczytywać akcje i je potwierdzać.
/insights/{insight_id}/act · /insights/runDziałanie na podstawie wniosku (zapisuje ceny) i ponowne przeliczanie wniosków.
/admin/… · /internal/…Wewnętrzna administracja platformy.

Webhooki

4pricing może wysyłać zdarzenia na Twój adres (webhook): wykonuje POST z JSON-em za każdym razem, gdy coś się wydarzy, więc Twój system nie musi ciągle pytać.

Na konto przypada jeden adres webhooka; trafiają na niego wszystkie typy zdarzeń. Rozróżnisz je po polu event — alert jest jedynym zdarzeniem bez tego pola.

Włączanie

  • Ustaw alert_webhook_url (publiczny adres http/https na porcie 80 lub 443), alert_webhook_secret oraz alert_webhook_enabled: true — w panelu lub przez PUT /settings/.
  • Adres wskazujący na sieć prywatną lub wewnętrzną jest odrzucany kodem 422. Przekierowania nie są śledzone.
  • Dla briefing.ready włącz także briefing_webhook_enabled. price.apply i price.revert są wysyłane tylko dla grup powiązanych z Twoim sklepem przez store_kind = webhook i tylko wtedy, gdy ustawiono sekret.
bash
curl -X PUT https://4pricing.net/api/v1/pricing/settings/ \
  -H "X-API-Key: WKLEJ_TUTAJ_KLUCZ" \
  -H "Content-Type: application/json" \
  -d '{"alert_webhook_url":"https://your-shop.example/4pricing-webhook.php","alert_webhook_secret":"TWOJ_SEKRET_WEBHOOKA","alert_webhook_enabled":true,"briefing_webhook_enabled":true}'

Zdarzenia

ZdarzenieZnaczenie
alertUruchomił się alert cenowy. Treść: event_id (deduplikuj po nim), alert_id, alert_type, message, message_code, message_params, price_cents, currency, triggered_at, product, group, panel_url. Bez pola event.
price.applyZatwierdzona cena do zastosowania w Twoim sklepie: action_id, group (id, name, sku, ean, store_product_id), old_price_cents, new_price_cents, currency, reason_code, mode i confirm.path.
price.revertPowrót do poprzedniej ceny. Ta sama treść co w price.apply; zastosuj ją i potwierdź w ten sam sposób.
briefing.readyDzienne podsumowanie jest gotowe: day, headline, summary, sections, total_value_cents (tylko z Twojej sprzedaży), currency, panel_url.

Nagłówki każdego zapytania webhooka

NagłówekZnaczenie
X-4Pricing-TimestampKiedy zapytanie zostało wysłane, w sekundach Unix. Odrzucaj zapytania, które są zbyt stare (na przykład ponad 5 minut).
X-4Pricing-Signaturesha256= a po nim szesnastkowy HMAC-SHA256 tekstu „<timestamp>.<raw body>”, obliczony z Twoim sekretem webhooka. Obecny, gdy ustawiono sekret (zawsze przy price.apply i price.revert).
Content-Typeapplication/json; charset=utf-8
User-Agent4pricing-alerts/1.0

Weryfikacja podpisu

Oblicz podpis ponownie z nagłówka timestamp i SUROWEJ treści, która dotarła, porównaj go w stałym czasie i sprawdź znacznik czasu. Dopiero wtedy przetwarzaj zdarzenie. Gdy je przyjmiesz, odpowiedz dowolnym kodem 2xx.

php
<?php
$secret = 'TWOJ_SEKRET_WEBHOOKA';

// Użyj SUROWEJ treści, dokładnie takiej, jaka dotarła — nie ponownie zakodowanego JSON-a
$body = file_get_contents('php://input');
$timestamp = isset($_SERVER['HTTP_X_4PRICING_TIMESTAMP']) ? $_SERVER['HTTP_X_4PRICING_TIMESTAMP'] : '';
$signature = isset($_SERVER['HTTP_X_4PRICING_SIGNATURE']) ? $_SERVER['HTTP_X_4PRICING_SIGNATURE'] : '';
$expected = 'sha256=' . hash_hmac('sha256', $timestamp . '.' . $body, $secret);

// Błędny podpis lub starszy niż 5 minut: odrzuć
if (!hash_equals($expected, $signature) || abs(time() - (int) $timestamp) > 300) {
    http_response_code(401);
    exit;
}

$event = json_decode($body, true);
if (isset($event['event']) && ($event['event'] === 'price.apply' || $event['event'] === 'price.revert')) {
    // Zastosuj new_price_cents w produkcie w swoim sklepie (dopasuj go po sku lub store_product_id)
    // $event['group']['sku'], $event['new_price_cents'], $event['currency']
    // Potem potwierdź: POST /actions/{action_id}/confirm ze swoim kluczem API
}
http_response_code(200);
echo 'ok';
javascript
// Node.js, no package needed
const http = require("http");
const crypto = require("crypto");
const SECRET = process.env.WEBHOOK_SECRET; // TWOJ_SEKRET_WEBHOOKA

http.createServer((req, res) => {
  const chunks = [];
  req.on("data", (c) => chunks.push(c));
  req.on("end", () => {
    // Użyj SUROWEJ treści, dokładnie takiej, jaka dotarła — nie ponownie zakodowanego JSON-a
    const body = Buffer.concat(chunks);
    const ts = String(req.headers["x-4pricing-timestamp"] || "");
    const sig = String(req.headers["x-4pricing-signature"] || "");
    const expected = "sha256=" + crypto.createHmac("sha256", SECRET).update(ts + ".").update(body).digest("hex");
    const fresh = Math.abs(Date.now() / 1000 - Number(ts)) <= 300;
    const same = sig.length === expected.length && crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
    if (!same || !fresh) {
      // Błędny podpis lub starszy niż 5 minut: odrzuć
      res.writeHead(401);
      return res.end();
    }
    const event = JSON.parse(body.toString("utf8"));
    if (event.event === "price.apply" || event.event === "price.revert") {
      // Zastosuj new_price_cents w produkcie w swoim sklepie (dopasuj go po sku lub store_product_id)
      // Potem potwierdź: POST /actions/{action_id}/confirm ze swoim kluczem API
    }
    res.writeHead(200);
    res.end("ok");
  });
}).listen(3000);
python
# Python 3, standard library only
import hashlib
import hmac
import time

SECRET = "TWOJ_SEKRET_WEBHOOKA"


def is_valid(raw_body: bytes, timestamp: str, signature: str) -> bool:
    # Użyj SUROWEJ treści, dokładnie takiej, jaka dotarła — nie ponownie zakodowanego JSON-a
    if not timestamp.isdigit() or abs(time.time() - int(timestamp)) > 300:
        return False
    expected = "sha256=" + hmac.new(
        SECRET.encode(), timestamp.encode() + b"." + raw_body, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature)

Dostarczanie i ponowienia

  • Alerty: przy błędzie połączenia lub DNS, kodzie 429 albo 5xx zapytanie jest ponawiane z wykładniczym odstępem, maksymalnie 5 prób. Każdy inny kod 4xx jest ostateczny.
  • Jeśli zapytanie wyszło, ale odpowiedź nie nadeszła w ciągu 10 sekund, nie jest wysyłane ponownie (by uniknąć duplikatu) — rzadko możesz mimo to dostać duplikat, więc deduplikuj po event_id.
  • price.apply i price.revert są wysyłane jeden raz: jeśli dostarczenie się nie powiedzie, akcja otrzymuje status failed. Deduplikuj po action_id.
  • briefing.ready jest wysyłane raz dziennie.

Potwierdzanie zastosowanej ceny

  • price.apply nie jest uznawane za zastosowane, dopóki Twój system tego nie potwierdzi. Po zmianie ceny w sklepie wywołaj POST /actions/{action_id}/confirm ze swoim kluczem API: akcja przechodzi z „wysłana” do „zastosowana”.
  • Podwójne potwierdzenie jest nieszkodliwe — akcja, która jest już zastosowana, zostanie zwrócona bez zmian.
bash
curl -X POST https://4pricing.net/api/v1/pricing/actions/ACTION_ID/confirm \
  -H "X-API-Key: WKLEJ_TUTAJ_KLUCZ"

Przykładowa treść

json · price.apply
{
  "event": "price.apply",
  "action_id": "8d0f2c4e-0b7a-4f7e-9d61-3c2b1a0e9f55",
  "tenant_id": "…",
  "group": {
    "id": "2fa912df-440c-4ddf-896a-5d558d56085f",
    "name": "Canon RF 50mm F1.8 STM",
    "sku": "4515C005AA",
    "ean": "4549292181623",
    "store_product_id": "1042"
  },
  "old_price_cents": 124900,
  "new_price_cents": 118699,
  "currency": "RON",
  "reason_code": "undercut",
  "mode": "manual",
  "confirm": { "method": "POST", "path": "/api/v1/pricing/actions/8d0f2c4e-0b7a-4f7e-9d61-3c2b1a0e9f55/confirm" }
}
json · alert
{
  "event_id": 18342,
  "alert_id": "c1b5…",
  "alert_type": "competitor_undercut",
  "tenant_id": "…",
  "message_code": "competitor_undercut",
  "message": "…",
  "message_params": { "…": "…" },
  "price_cents": 118990,
  "currency": "RON",
  "triggered_at": "2026-10-13T07:05:12",
  "product": { "id": "…", "name": "…", "url": "https://…", "retailer": "…", "current_price_cents": 118990, "in_stock": true },
  "group": { "id": "…", "name": "Canon RF 50mm F1.8 STM", "sku": "4515C005AA" },
  "panel_url": "https://panel.4pricing.net/…"
}

Błędy

Błędy przychodzą z właściwym statusem HTTP i treścią JSON {"detail": …}. detail to tekst, obiekt z kodem, który możesz obsłużyć w swoim programie, albo — przy 422 — lista nieprawidłowych pól.

StatusKodZnaczenie
401—Klucz API jest nieobecny, błędny lub unieważniony.
402plan_requiredKonto nie ma aktywnej subskrypcji 4pricing.
402plan_limitZostałby przekroczony limit planu (monitorowane adresy URL, sklepy konkurencji) albo odświeżenie nastąpiło przed minimalnym odstępem. Komunikat wskazuje, który to limit.
402insufficient_creditsZa mało kredytów na wywołanie, które odczytuje stronę sklepu. Nic nie zostało odczytane ani pobrane.
403—Zablokowane przez zaporę, zanim żądanie dotarło do API — zwykle z powodu ogólnego User-Agent, takiego jak Python-urllib. Wyślij własny User-Agent.
404—Zasób nie istnieje, nie należy do Twojego konta albo ścieżka nie jest dostępna przez API.
409recommendation_moved · own_from_listing · invalid_state · webhook_secret_requiredKonflikt: rekomendowana cena się zmieniła (recommendation_moved), akcja jest w innym stanie (invalid_state), wymagany jest sekret webhooka albo operacja nie dotyczy tego elementu.
422—Nieprawidłowe dane, na przykład adres URL bez http/https albo brakujące wymagane pole. detail wymienia pola.
429—Ponad 60 zapytań na minutę dla konta (albo zbyt wiele nieprawidłowych kluczy). Poczekaj tyle sekund, ile wskazuje Retry-After.
503credit_wallet_unavailablePortfela kredytów nie można teraz odczytać. Spróbuj później; nic nie zostało pobrane.

Treść błędów

json
{"detail": "Invalid or missing API key"}
{"detail": {"code": "plan_required", "message": "…"}}
{"detail": {"code": "insufficient_credits", "message": "…"}}
{"detail": [{"loc": ["body", "price_cents"], "msg": "…", "type": "…"}]}

Przykłady kodu

Ten sam odczyt w czterech językach, z pauzą i ponowieniem po kodzie 429, a następnie wysyłanie sprzedaży. Zastąp WKLEJ_TUTAJ_KLUCZ swoim kluczem (albo ustaw zmienną środowiskową PRICING_API_KEY).

Node.js: odczytaj porównywane produkty

javascript
// Node.js 18+ (fetch is built in, no package needed)
const API_KEY = process.env.PRICING_API_KEY; // WKLEJ_TUTAJ_KLUCZ
const BASE = "https://4pricing.net/api/v1/pricing";

async function call(path, options = {}) {
  for (let attempt = 0; attempt < 3; attempt++) {
    const res = await fetch(BASE + path, {
      ...options,
      headers: { "X-API-Key": API_KEY, "Content-Type": "application/json", ...(options.headers || {}) },
    });
    if (res.status === 429) {
      // Ponad 60 zapytań na minutę: poczekaj tyle sekund, ile wskazuje Retry-After, i spróbuj ponownie
      const wait = Number(res.headers.get("Retry-After") || 60);
      await new Promise((r) => setTimeout(r, wait * 1000));
      continue;
    }
    if (!res.ok) throw new Error(res.status + " " + (await res.text()));
    return res.status === 204 ? null : res.json();
  }
  throw new Error("rate limited");
}

async function main() {
  // Twoje porównywane produkty: Twoja cena, najtańsza konkurencja, werdykt
  const groups = await call("/groups/");
  for (const g of groups) {
    console.log(g.name, g.own_price_cents_effective, g.min_competitor_cents, g.verdict);
  }
}

main().catch((err) => {
  console.error(err.message);
  process.exit(1);
});

Python: odczytaj porównywane produkty

python
# Python 3, standard library only
import json
import os
import time
import urllib.error
import urllib.request

API_KEY = os.environ["PRICING_API_KEY"]  # WKLEJ_TUTAJ_KLUCZ
BASE = "https://4pricing.net/api/v1/pricing"


def call(path, method="GET", payload=None):
    data = json.dumps(payload).encode() if payload is not None else None
    for _ in range(3):
        req = urllib.request.Request(BASE + path, data=data, method=method, headers={
            "X-API-Key": API_KEY, "Content-Type": "application/json", "Accept": "application/json",
            # Ustaw własny User-Agent: domyślny w niektórych bibliotekach HTTP (Python urllib) jest blokowany kodem 403
            "User-Agent": "my-shop-integration/1.0",
        })
        try:
            with urllib.request.urlopen(req, timeout=30) as res:
                body = res.read()
                return json.loads(body) if body else None
        except urllib.error.HTTPError as err:
            if err.code == 429:
                # Ponad 60 zapytań na minutę: poczekaj tyle sekund, ile wskazuje Retry-After, i spróbuj ponownie
                time.sleep(int(err.headers.get("Retry-After", "60")))
                continue
            raise
    raise RuntimeError("rate limited")


# Twoje porównywane produkty: Twoja cena, najtańsza konkurencja, werdykt
for g in call("/groups/"):
    print(g["name"], g["own_price_cents_effective"], g["min_competitor_cents"], g["verdict"])

curl: wyślij dzienną sprzedaż

bash
curl -X POST https://4pricing.net/api/v1/pricing/sales/bulk \
  -H "X-API-Key: WKLEJ_TUTAJ_KLUCZ" \
  -H "Content-Type: application/json" \
  -d '{"rows":[{"sku":"BIALA-KOSZULKA-M","day":"2026-10-12","units_sold":7,"revenue_cents":34993}]}'

PHP: wyślij dzienną sprzedaż

php
<?php
$apiKey = 'WKLEJ_TUTAJ_KLUCZ';

// Dzienna sprzedaż na produkt (według sku lub group_id), do 2000 wierszy na zapytanie
$rows = [
    ['sku' => 'BIALA-KOSZULKA-M', 'day' => '2026-10-12', 'units_sold' => 7, 'revenue_cents' => 34993],
];

$ch = curl_init('https://4pricing.net/api/v1/pricing/sales/bulk');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_USERAGENT => 'my-shop-integration/1.0',
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => ['X-API-Key: ' . $apiKey, 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => json_encode(['rows' => $rows]),
]);
$body = curl_exec($ch);
echo curl_getinfo($ch, CURLINFO_HTTP_CODE) . ' ' . $body;   // 200 {"upserted": 1, "skipped": []}

Najczęściej zadawane pytania

Czy muszę być programistą, żeby używać API 4pricing?

Nie. Szybki start daje Ci gotowy plik PHP: tworzysz klucz w panelu, wklejasz go do pliku, wgrywasz plik na hosting i otwierasz go w przeglądarce. Przy bardziej zaawansowanych integracjach (ERP, platforma sklepowa) programista może skorzystać z opisu endpointów i specyfikacji OpenAPI.

Ile kosztuje API 4pricing?

API jest wliczone w każdą subskrypcję 4pricing, z tymi samymi limitami co panel. Odczyt Twoich danych jest bezpłatny; kredyty zużywają tylko wywołania, które odczytują stronę sklepu (dodanie nowego adresu URL, odświeżenie, wyszukiwanie na żywo, znajdowanie konkurentów) — tak samo jak w panelu.

Które wywołania zużywają kredyty?

POST /products/, POST /products/{product_id}/refresh, POST /groups/{group_id}/refresh, POST /groups/{group_id}/members z nowym adresem URL, POST /groups/{group_id}/suggestions oraz POST /search/. Jeśli saldo nie wystarcza, dostajesz 402 insufficient_credits i nic nie jest odczytywane.

Czy ceny wysyłane przez API wliczają się do limitu adresów URL w moim planie?

Nie. Liczą się tylko adresy, które 4pricing odczytuje ze strony — Twoje własne strony produktów i każda strona konkurenta osobno. Ceny wysłane przez POST /own-products/ lub /own-products/bulk nie liczą się ani jako adresy URL, ani jako kredyty.

Czy mogę ograniczyć, do czego ma dostęp klucz?

Nie, nie ma zakresów uprawnień: klucz widzi i może zmieniać całe Twoje konto 4pricing. Używaj osobnego klucza dla każdej integracji i unieważniaj każdy klucz, którego już nie używasz; unieważnienie działa natychmiast.

Co się stanie, jeśli wyślę więcej niż 60 zapytań na minutę?

Dostaniesz 429 z nagłówkiem Retry-After. Limit dotyczy konta i jest wspólny dla wszystkich Twoich kluczy. Poczekaj liczbę sekund podaną w Retry-After i spróbuj ponownie; przy wielu produktach używaj wywołań zbiorczych (do 2000 wierszy na zapytanie).

Jak sprawić, by rekomendowana cena trafiała do mojego sklepu automatycznie?

Powiąż grupę ze sklepem przez store_kind = webhook, ustaw adres i sekret webhooka i obsłuż zdarzenie price.apply: zmień cenę w sklepie, a następnie wywołaj POST /actions/{action_id}/confirm. Zatwierdzanie zmiany ceny pozostaje decyzją podejmowaną w panelu.

Czy istnieje SDK albo gotowa wtyczka?

Nie ma oficjalnego SDK ani wtyczki. API to zwykły REST z JSON-em, więc działa każdy język, który potrafi wykonywać zapytania HTTPS; specyfikację OpenAPI można załadować do narzędzi, które automatycznie generują klienta.