Développeurs

API 4pricing pour développeurs

Connectez votre propre système (CRM, ERP, boutique en ligne) à 4pricing et interrogez les prix des concurrents, les groupes de comparaison et les alertes directement depuis votre code.

URL de base: https://4pricing.net/api/v1/pricing · Spécification OpenAPI (JSON)

Intégration rapide en 3 étapes

C'est le chemin le plus court pour afficher vos données 4pricing sur votre propre site. Vous copiez un seul fichier, vous y collez votre clé et vous le déposez sur votre hébergement — sans framework, sans installation.

Ce dont vous avez besoin
  • Un abonnement 4pricing actif (l'API est incluse dans tous les forfaits).
  • Un hébergement avec PHP — presque tous les hébergements mutualisés en proposent (cPanel, Plesk et équivalents).
  • Un moyen de téléverser un fichier : le gestionnaire de fichiers de votre hébergeur ou un logiciel FTP.
  1. Étape 1: Créez votre clé API

    Connectez-vous à panel.4pricing.net et ouvrez Veille tarifaire → API et clés.

    Cliquez sur « Générer la clé », donnez-lui un nom (par exemple « ma boutique ») et copiez la clé qui commence par prc_live_. Elle n'est affichée qu'une seule fois — si vous la perdez, créez-en une autre et révoquez l'ancienne.

    Ouvrir API et clés dans le panneau →

  2. Étape 2: Copiez le fichier prêt à l'emploi et collez votre clé

    Copiez le fichier PHP ci-dessous dans un éditeur de texte (Bloc-notes, TextEdit ou VS Code) et enregistrez-le sous le nom 4pricing-prix.php.

    php4pricing-prix.php
    <?php
    // =====================================================================
    // COLLEZ ICI VOTRE CLÉ API (panel.4pricing.net → API et clés), entre les guillemets
    $apiKey = 'COLLEZ_VOTRE_CLE_ICI';
    // =====================================================================
    
    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('La clé API est manquante : ouvrez le fichier et collez votre clé sur la ligne indiquée.') . '</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('Impossible de se connecter à 4pricing :' . ' ' . curl_error($ch)) . '</p>');
    }
    if ($status !== 200) {
        $hints = [401 => 'la clé API est erronée ou a été révoquée', 402 => 'le compte n\'a pas d\'abonnement 4pricing actif (ou pas assez de crédits)', 429 => 'trop de requêtes en une minute, réessayez dans une minute'];
        $hint = isset($hints[$status]) ? ' — ' . $hints[$status] : '';
        exit('<p>' . h('4pricing a répondu avec l\'erreur' . ' ' . $status . $hint) . '</p><pre>' . h($body) . '</pre>');
    }
    
    $groups = json_decode($body, true);
    $verdicts = [
        'cheapest' => 'Vous êtes le moins cher',
        'too_cheap' => 'Bien moins cher que le marché — vous pouvez augmenter le prix',
        'competitive' => 'Compétitif',
        'too_expensive' => 'Plus cher que la plupart des concurrents',
        'no_competitors' => 'Pas encore de prix concurrent',
        'no_own_price' => 'Votre prix est manquant',
    ];
    
    echo '<!doctype html><html><head><meta charset="utf-8"><title>' . h('Mes produits surveillés') . '</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('Mes produits surveillés') . '</h1>';
    
    if (!$groups) {
        echo '<p>' . h('Vous n\'avez pas encore de produit comparé.') . '</p>';
    } else {
        echo '<table><tr><th>' . h('Produit') . '</th><th>' . h('SKU') . '</th>';
        echo '<th>' . h('Votre prix') . '</th><th>' . h('Concurrent le moins cher') . '</th>';
        echo '<th>' . h('Écart') . '</th><th>' . h('Verdict') . '</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>';
    
    Remplacez COLLEZ_VOTRE_CLE_ICI par votre clé, en conservant les guillemets qui l'entourent. C'est la seule ligne à modifier.
  3. Étape 3: Déposez le fichier sur votre site et ouvrez-le dans votre navigateur

    Déposez 4pricing-prix.php sur votre site avec le gestionnaire de fichiers ou par FTP, dans le même dossier que votre site (en général public_html).

    Ouvrez https://votre-site/4pricing-prix.php dans le navigateur. Vous verrez un tableau avec chaque produit comparé : votre prix, le prix du concurrent le moins cher, l'écart et le verdict.

Le fichier : la liste de vos produits avec le prix du concurrent le moins cher

Le fichier demande à 4pricing vos produits comparés (GET /groups/) et les affiche sous forme de tableau. La lecture des données est gratuite et ne consomme pas de crédits.

  • « Votre prix » est le prix que 4pricing connaît pour vous ; « Concurrent le moins cher » est le prix le plus bas trouvé parmi les concurrents que vous surveillez.
  • Les prix sont affichés en unités (12999 centimes deviennent 129,99) ; un tiret (—) signifie que 4pricing n'a pas encore de prix, et non que le prix est zéro.
  • Si vous voyez une erreur à la place du tableau, le message vous indique quoi corriger : clé erronée, abonnement inactif ou trop de requêtes en une minute.

Deuxième recette : envoyer votre prix

À utiliser quand 4pricing doit connaître votre propre prix sans le lire sur la page de votre boutique — par exemple directement depuis la base de données de votre boutique. L'envoi de vos prix est gratuit (sans crédits) et ne compte pas dans la limite d'URL surveillées de votre forfait.

ChampSignification
skuvotre code produit ; 4pricing retrouve le produit grâce à lui, ou le crée la première fois
namele nom du produit, tel que vous voulez le voir dans 4pricing
urlfacultatif : l'adresse de la page du produit dans votre boutique (elle n'est jamais lue)
price_centsle prix multiplié par 100, sans décimales : 49,99 → 4999
currencyle code de la devise, par exemple EUR, GBP ou RON (RON si absent)
php4pricing-envoi-prix.php
<?php
// =====================================================================
// COLLEZ ICI VOTRE CLÉ API (panel.4pricing.net → API et clés), entre les guillemets
$apiKey = 'COLLEZ_VOTRE_CLE_ICI';
// =====================================================================

// VOS PRODUITS : un bloc par produit. price_cents = prix x 100 (49,99 devient 4999).
$products = [
    [
        'sku' => 'TSHIRT-BLANC-M',
        'name' => 'T-shirt blanc, taille M',
        'url' => 'https://votre-boutique.example/t-shirt-blanc-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('La clé API est manquante : ouvrez le fichier et collez votre clé sur la ligne indiquée.') . '</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('Impossible de se connecter à 4pricing :' . ' ' . curl_error($ch)) . '</p>');
}
if ($status !== 200) {
    $hints = [401 => 'la clé API est erronée ou a été révoquée', 402 => 'le compte n\'a pas d\'abonnement 4pricing actif (ou pas assez de crédits)', 429 => 'trop de requêtes en une minute, réessayez dans une minute'];
    $hint = isset($hints[$status]) ? ' — ' . $hints[$status] : '';
    exit('<p>' . h('4pricing a répondu avec l\'erreur' . ' ' . $status . $hint) . '</p><pre>' . h($body) . '</pre>');
}

$result = json_decode($body, true);
echo '<h1>' . h('Prix envoyés à 4pricing') . '</h1>';
echo '<p>' . h('Nouveaux produits créés :') . ' ' . (int) $result['created'] . '</p>';
echo '<p>' . h('Produits mis à jour :') . ' ' . (int) $result['updated'] . '</p>';
if (!empty($result['errors'])) {
    echo '<p>' . h('Lignes avec problèmes :') . '</p><ul>';
    foreach ($result['errors'] as $error) {
        echo '<li>' . h($error) . '</li>';
    }
    echo '</ul>';
}
  • Enregistrez-le sous le nom 4pricing-envoi-prix.php, collez votre clé, modifiez les lignes de produits, déposez-le et ouvrez-le une fois : la page affiche combien de produits ont été créés et combien mis à jour.
  • Chaque requête peut contenir jusqu'à 2 000 produits ; une ligne erronée est signalée et les autres sont quand même enregistrées. Renvoyer le même sku met le prix à jour.

Les mêmes appels avec curl

Si vous préférez le terminal, ces deux commandes font exactement la même chose que les deux fichiers PHP :

bash
curl https://4pricing.net/api/v1/pricing/groups/ \
  -H "X-API-Key: COLLEZ_VOTRE_CLE_ICI"
bash
curl -X POST https://4pricing.net/api/v1/pricing/own-products/bulk \
  -H "X-API-Key: COLLEZ_VOTRE_CLE_ICI" \
  -H "Content-Type: application/json" \
  -d '{"items":[{"sku":"TSHIRT-BLANC-M","name":"T-shirt blanc, taille M","url":"https://votre-boutique.example/t-shirt-blanc-m","price_cents":4999,"currency":"EUR"}]}'
Gardez la clé en lieu sûr
  • La clé donne accès à tout votre compte 4pricing. Conservez-la uniquement dans des fichiers côté serveur (PHP, votre backend) — jamais dans du JavaScript de navigateur ni dans un dépôt public.
  • Toute personne qui connaît l'adresse de la page déposée peut voir le tableau des prix (pas la clé). Donnez au fichier un nom difficile à deviner, protégez le dossier par un mot de passe, ou supprimez-le quand vous n'en avez plus besoin.
  • Si une clé fuit, révoquez-la dans API et clés — elle cesse de fonctionner immédiatement — et créez-en une nouvelle.

Authentification

  • Chaque requête transporte votre clé dans l'en-tête X-API-Key. Authorization: Bearer prc_live_… fonctionne aussi (uniquement pour les clés qui commencent par prc_).
  • Il n'y a pas de portées (scopes) : une clé peut lire et modifier tout ce qui se trouve dans votre compte 4pricing. Créez une clé par intégration (boutique, ERP, rapport) afin de pouvoir en révoquer une sans arrêter les autres.
  • Une clé manquante, erronée ou révoquée reçoit 401. La révocation est effective immédiatement. Trop de clés invalides en une minute reçoivent 429.
  • Les clés se créent, se consultent et se révoquent uniquement dans le panneau (Veille tarifaire → API et clés) ; l'API elle-même ne peut pas gérer les clés. Créer une clé nécessite un abonnement 4pricing actif.
http
X-API-Key: prc_live_…
# or
Authorization: Bearer prc_live_…

URL de base et conventions

  • Tous les chemins de cette documentation sont relatifs à l'URL de base — /groups/ signifie https://4pricing.net/api/v1/pricing/groups/.
  • Les requêtes et les réponses sont en JSON (Content-Type: application/json).
  • Les montants sont des nombres entiers dans la plus petite unité monétaire (centimes) : price_cents = 12999 signifie 129,99. Les pourcentages sont en points de base (100 = 1 %).
  • Une valeur inconnue vaut null, jamais 0 — affichez-la sous la forme « — ».
  • Les collections s'appellent avec une barre oblique finale (/products/, /groups/, /insights/).
  • Les listes paginées renvoient le total dans l'en-tête X-Total-Count (par exemple GET /products/?skip=0&limit=200).
  • Envoyez un en-tête User-Agent qui nomme votre intégration (par exemple my-shop-integration/1.0). Le pare-feu placé devant l'API répond 403 à certaines valeurs génériques par défaut de bibliothèques, comme Python-urllib.

Limite de requêtes, abonnement et limites du forfait

Limite de requêtes

  • 60 requêtes par minute et par COMPTE, sur une fenêtre glissante — toutes les clés d'un même compte se partagent les mêmes 60.
  • Chaque réponse contient X-RateLimit-Limit, X-RateLimit-Remaining et X-RateLimit-Reset (la durée de la fenêtre, en secondes).
  • Au-delà de la limite, vous recevez 429 avec un en-tête Retry-After (en secondes). Attendez ce délai, puis réessayez — les exemples ci-dessous le font pour vous.
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"}

Abonnement et limites du forfait

  • L'API nécessite un abonnement 4pricing actif ; sans lui, chaque requête reçoit 402 avec le code plan_required.
  • Chaque forfait inclut l'API avec les mêmes limites que le panneau. Dépasser une limite en ajoutant ou en réactivant quelque chose renvoie 402 avec le code plan_limit et un message qui indique quelle limite.
LimiteSignification
URL surveilléesChaque adresse de page produit que 4pricing lit compte séparément : votre propre page et chaque page concurrente. Les prix que vous envoyez avec /own-products ne comptent pas.
Boutiques concurrentesLe nombre de sites concurrents distincts (domaines) que vous surveillez.
Intervalle minimal de vérificationLa fréquence à laquelle la même URL peut être vérifiée. Les intervalles plus courts sont automatiquement relevés au minimum de votre forfait ; actualiser une URL trop tôt renvoie 402 plan_limit.

Quels appels consomment des crédits

La lecture d'une page de boutique consomme des crédits du portefeuille de votre compte. Les appels ci-dessous vérifient le solde AVANT de lire quoi que ce soit : s'il est insuffisant, vous recevez 402 insufficient_credits, et si le portefeuille est momentanément illisible, vous recevez 503 credit_wallet_unavailable (réessayez plus tard). Dans les deux cas, rien n'est lu et rien n'est facturé.

Appels qui consomment des crédits

MéthodeEndpointCe que ça faitCoût
POST/groups/{group_id}/membersAjouter une URL au groupe, par product_id ou à partir d'une nouvelle adresse (une nouvelle adresse est lue immédiatement)Crédits
POST/groups/{group_id}/refreshVérifier maintenant chaque URL du groupeCrédits
POST/groups/{group_id}/suggestions« Trouver des concurrents » : URL concurrentes proposées, avec un score et la raisonCrédits
POST/products/Commencer à surveiller une URL (url, name, role own ou competitor) — elle est lue immédiatementCrédits
POST/products/{product_id}/refreshVérifier maintenant le prix de cette URL (en respectant l'intervalle minimal de votre forfait)Crédits
POST/search/Rechercher en direct le prix d'un produit chez les revendeurs (des crédits pour chaque revendeur interrogé)Crédits

Appels gratuits

  • Toute lecture (GET) : produits, groupes, comparaisons, historique, alertes, insights, briefings, crédits, statistiques.
  • POST /own-products/ et POST /own-products/bulk — vos propres prix.
  • POST /sales/bulk — vos ventes.
  • Alertes, paramètres, confirmations et tout le reste, qui ne lit pas de page de boutique.
  • La surveillance planifiée des URL que vous suivez consomme aussi des crédits, à chaque vérification ; GET /credits/ affiche votre solde et la prévision.
  • POST /products/import ajoute de nombreuses URL d'un coup sans les lire immédiatement : elles sont vérifiées — et facturées — par la surveillance planifiée.

Référence des endpoints

Toutes les opérations accessibles avec une clé, regroupées selon leur usage. La spécification OpenAPI décrit chacune champ par champ, avec les corps exacts de requête et de réponse.

Vos propres prix

Indiquez directement votre prix à 4pricing, sans lire la page de votre boutique. Gratuit.

MéthodeEndpointCe que ça faitCoût
POST/own-products/Envoyer votre prix actuel pour un produit (retrouvé par sku, sinon par nom ; créé s'il n'existe pas)Gratuit
POST/own-products/bulkEnvoyer vos prix pour jusqu'à 2 000 produits en une seule requête ; les lignes erronées sont signalées, les autres sont enregistréesGratuit

Produits comparés (groupes)

Un groupe est l'un de vos produits, avec les pages concurrentes qui vendent la même chose. Il contient le verdict et le prix recommandé.

MéthodeEndpointCe que ça faitCoût
GET/groups/Tous les produits comparés, chacun avec votre prix, le prix du concurrent le moins cher, le verdict et le prix recommandéGratuit
POST/groups/Créer un produit comparé (nom, sku, votre prix, coût, stratégie de prix)Gratuit
GET/groups/{group_id}Un produit comparéGratuit
PUT/groups/{group_id}Mettre à jour le prix, le coût, la stratégie, l'intervalle de vérification ou le lien avec la boutique (store_kind)Gratuit
DELETE/groups/{group_id}Supprimer le groupe ; ses URL restent surveilléesGratuit
GET/groups/{group_id}/comparisonVotre position face à chaque concurrent, avec le prix recommandé et la manière dont il a été calculéGratuit
GET/groups/{group_id}/historyHistorique des prix de chaque URL du groupeGratuit
GET/groups/seriesVotre position sur le marché, jour après jour, sur l'ensemble des produitsGratuit
POST/groups/{group_id}/membersAjouter une URL au groupe, par product_id ou à partir d'une nouvelle adresse (une nouvelle adresse est lue immédiatement)Crédits
DELETE/groups/{group_id}/members/{product_id}Retirer une URL du groupe (elle reste surveillée)Gratuit
POST/groups/{group_id}/refreshVérifier maintenant chaque URL du groupeCrédits
POST/groups/{group_id}/apply-recommendedFaire du prix recommandé votre propre prix dans 4pricing (envoyez le prix que vous avez vu ; 409 s'il a changé)Gratuit
GET/groups/suggestions/sourcesSources disponibles pour « Trouver des concurrents »Gratuit
POST/groups/{group_id}/suggestions« Trouver des concurrents » : URL concurrentes proposées, avec un score et la raisonCrédits

URL surveillées

Une ligne par adresse de page que 4pricing lit, la vôtre ou celle d'un concurrent (rôle own ou competitor).

MéthodeEndpointCe que ça faitCoût
GET/products/URL surveillées, paginées (skip, limit jusqu'à 500 ; total dans X-Total-Count)Gratuit
POST/products/Commencer à surveiller une URL (url, name, role own ou competitor) — elle est lue immédiatementCrédits
POST/products/importAjouter de nombreuses URL d'un coup ; elles sont lues plus tard par la surveillance planifiéeGratuit
GET/products/exportExport CSV des URL activesGratuit
GET/products/{product_id}Une URL surveillée avec son dernier prixGratuit
PATCH/products/{product_id}Modifier le nom, la catégorie ou l'intervalle de vérificationGratuit
DELETE/products/{product_id}Arrêter de surveiller une URL (elle est conservée comme inactive)Gratuit
POST/products/{product_id}/refreshVérifier maintenant le prix de cette URL (en respectant l'intervalle minimal de votre forfait)Crédits
GET/products/{product_id}/historyHistorique des prix d'une URLGratuit
GET/products/sparklinesUn court historique de prix pour plusieurs URL à la foisGratuit
GET/products/price-changesURL dont le prix a changé lors de la dernière vérificationGratuit

Consultez dès maintenant le prix d'un produit chez les revendeurs.

MéthodeEndpointCe que ça faitCoût
POST/search/Rechercher en direct le prix d'un produit chez les revendeurs (des crédits pour chaque revendeur interrogé)Crédits

Alertes

Règles de prix et boîte de réception des alertes déclenchées.

MéthodeEndpointCe que ça faitCoût
GET/alerts/Vos alertes de prixGratuit
POST/alerts/Créer une alerte (prix en dessous/au-dessus d'un seuil, baisse en %, retour en stock, un concurrent vous passe sous le prix…)Gratuit
DELETE/alerts/{alert_id}Supprimer une alerteGratuit
POST/alerts/{alert_id}/rearmRéarmer une alerte qui s'est déclenchéeGratuit
GET/alerts/eventsBoîte de réception des alertes déclenchéesGratuit
GET/alerts/events/unread-countCombien d'alertes non lues vous avezGratuit
POST/alerts/events/read-allMarquer les alertes comme lues (éventuellement seulement celles antérieures à un moment donné)Gratuit
POST/alerts/events/{event_id}/readMarquer une alerte comme lueGratuit

Crédits

Solde, prévision et tous les mouvements de crédits.

MéthodeEndpointCe que ça faitCoût
GET/credits/Solde de crédits et prévision de consommationGratuit
GET/credits/ledgerChaque mouvement de créditsGratuit
GET/credits/by-productCrédits consommés par URL (total et 30 derniers jours)Gratuit

Vos ventes

Ventes quotidiennes par produit, utilisées pour calculer la valeur de chaque opportunité. Gratuit.

MéthodeEndpointCe que ça faitCoût
POST/sales/bulkVentes quotidiennes par produit (sku ou group_id, day, units_sold, revenue_cents ; stock_units et cost_cents facultatifs), jusqu'à 2 000 lignes ; renvoyer le même produit pour le même jour écrase la valeurGratuit

Insights, opportunités et briefings

Ce qui a changé, pourquoi c'est important et ce qu'il faut faire — plus le briefing quotidien.

MéthodeEndpointCe que ça faitCoût
GET/insights/Insights avec preuves et propositions de prix (X-Total-Count)Gratuit
GET/insights/{insight_id}Un insight en détailGratuit
POST/insights/{insight_id}/dismissIgnorer un insightGratuit
GET/opportunities/Synthèse des opportunités : valeur issue de vos ventes, séparée de l'estimation du marchéGratuit
GET/briefings/Historique des briefings quotidiensGratuit
GET/briefings/latestLe dernier briefing quotidienGratuit
POST/briefings/generateReconstruire le briefing du jour à partir des insights ouverts (n'envoie rien)Gratuit

Actions de prix

Changements de prix proposés, envoyés, appliqués ou annulés. Via l'API, vous pouvez les lire et confirmer ceux reçus par webhook.

MéthodeEndpointCe que ça faitCoût
GET/actions/Actions de prix : proposées, envoyées, appliquées, annuléesGratuit
POST/actions/{action_id}/confirmConfirmer que votre système a appliqué un prix reçu via price.apply ou price.revertGratuit

Paramètres

Paramètres du compte, y compris l'adresse et le secret du webhook.

MéthodeEndpointCe que ça faitCoût
GET/settings/Paramètres du compte (revendeurs, stratégie de repricing, envoi des alertes, webhook)Gratuit
PUT/settings/Modifier les paramètres, y compris alert_webhook_url, alert_webhook_secret et alert_webhook_enabledGratuit

Statistiques

Vue d'ensemble du compte et état de santé des vérifications de prix.

MéthodeEndpointCe que ça faitCoût
GET/stats/Statistiques du compte : URL, alertes, variations sur 24 heures, groupesGratuit
GET/stats/scrapersÉtat de santé des vérifications de prix par revendeurGratuit

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

Ce que l'API ne peut pas faire

Certaines choses restent volontairement dans le panneau, là où une personne connectée décide. Via l'API, ces chemins répondent 404 :

CheminPourquoi
/keys/…Création et révocation des clés — une clé ne peut pas créer d'autres clés.
/autopilot/…La politique du pilote automatique, qui décide de ce qui peut changer sans intervention humaine ; une clé divulguée ne doit pas pouvoir l'élargir.
/watchlists/…Les listes de surveillance, qui dépensent des crédits à chaque exécution.
/actions/{action_id}/approve · reject · revertApprouver, rejeter ou annuler un changement de prix est une décision qu'une personne prend dans le panneau. L'API peut seulement lire les actions et les confirmer.
/insights/{insight_id}/act · /insights/runAgir sur un insight (cela écrit des prix) et recalculer les insights.
/admin/… · /internal/…Administration interne de la plateforme.

Webhooks

4pricing peut envoyer des événements à une adresse de votre choix (un webhook) : il fait un POST JSON chaque fois que quelque chose se produit, de sorte que votre système n'a pas à interroger l'API en permanence.

Il y a une seule adresse de webhook par compte ; tous les types d'événements y arrivent. Distinguez-les grâce au champ event — l'alerte est le seul événement qui n'en a pas.

Activation

  • Renseignez alert_webhook_url (une adresse http/https publique sur le port 80 ou 443), alert_webhook_secret et alert_webhook_enabled: true — dans le panneau ou avec PUT /settings/.
  • Une adresse qui pointe vers un réseau privé ou interne est refusée avec 422. Les redirections ne sont pas suivies.
  • Pour briefing.ready, activez aussi briefing_webhook_enabled. price.apply et price.revert ne sont envoyés que pour les groupes liés à votre boutique avec store_kind = webhook, et seulement si un secret est défini.
bash
curl -X PUT https://4pricing.net/api/v1/pricing/settings/ \
  -H "X-API-Key: COLLEZ_VOTRE_CLE_ICI" \
  -H "Content-Type: application/json" \
  -d '{"alert_webhook_url":"https://your-shop.example/4pricing-webhook.php","alert_webhook_secret":"VOTRE_SECRET_WEBHOOK","alert_webhook_enabled":true,"briefing_webhook_enabled":true}'

Événements

ÉvénementSignification
alertUne alerte de prix s'est déclenchée. Corps : event_id (dédoublonnez dessus), alert_id, alert_type, message, message_code, message_params, price_cents, currency, triggered_at, product, group, panel_url. Pas de champ event.
price.applyUn prix approuvé à appliquer dans votre boutique : action_id, group (id, name, sku, ean, store_product_id), old_price_cents, new_price_cents, currency, reason_code, mode et confirm.path.
price.revertRevenir au prix précédent. Même corps que price.apply ; appliquez-le et confirmez-le de la même manière.
briefing.readyLe briefing quotidien est prêt : day, headline, summary, sections, total_value_cents (uniquement à partir de vos ventes), currency, panel_url.

En-têtes de chaque requête webhook

En-têteSignification
X-4Pricing-TimestampMoment d'envoi de la requête, en secondes Unix. Rejetez les requêtes trop anciennes (par exemple de plus de 5 minutes).
X-4Pricing-Signaturesha256= suivi du HMAC-SHA256 hexadécimal du texte « <timestamp>.<raw body> », calculé avec votre secret de webhook. Présent lorsqu'un secret est défini (toujours sur price.apply et price.revert).
Content-Typeapplication/json; charset=utf-8
User-Agent4pricing-alerts/1.0

Vérifier la signature

Recalculez la signature à partir de l'en-tête timestamp et du corps BRUT reçu, comparez-la en temps constant et vérifiez le timestamp. Ce n'est qu'ensuite que vous traitez l'événement. Répondez avec n'importe quel code 2xx une fois l'événement accepté.

php
<?php
$secret = 'VOTRE_SECRET_WEBHOOK';

// Utilisez le corps BRUT, exactement tel que reçu — pas un JSON ré-encodé
$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);

// Signature erronée ou vieille de plus de 5 minutes : rejetez la requête
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')) {
    // Appliquez new_price_cents au produit de votre boutique (retrouvez-le par sku ou store_product_id)
    // $event['group']['sku'], $event['new_price_cents'], $event['currency']
    // Puis confirmez : POST /actions/{action_id}/confirm avec votre clé 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; // VOTRE_SECRET_WEBHOOK

http.createServer((req, res) => {
  const chunks = [];
  req.on("data", (c) => chunks.push(c));
  req.on("end", () => {
    // Utilisez le corps BRUT, exactement tel que reçu — pas un JSON ré-encodé
    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) {
      // Signature erronée ou vieille de plus de 5 minutes : rejetez la requête
      res.writeHead(401);
      return res.end();
    }
    const event = JSON.parse(body.toString("utf8"));
    if (event.event === "price.apply" || event.event === "price.revert") {
      // Appliquez new_price_cents au produit de votre boutique (retrouvez-le par sku ou store_product_id)
      // Puis confirmez : POST /actions/{action_id}/confirm avec votre clé API
    }
    res.writeHead(200);
    res.end("ok");
  });
}).listen(3000);
python
# Python 3, standard library only
import hashlib
import hmac
import time

SECRET = "VOTRE_SECRET_WEBHOOK"


def is_valid(raw_body: bytes, timestamp: str, signature: str) -> bool:
    # Utilisez le corps BRUT, exactement tel que reçu — pas un JSON ré-encodé
    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)

Livraison et nouvelles tentatives

  • Alertes : en cas d'erreur de connexion ou DNS, de 429 ou de 5xx, la requête est renvoyée avec un backoff exponentiel, au maximum 5 tentatives. Tout autre 4xx est définitif.
  • Si la requête est partie mais qu'aucune réponse n'est arrivée dans les 10 secondes, elle n'est pas renvoyée (pour éviter un doublon) — vous pouvez encore, rarement, recevoir un doublon : dédoublonnez donc sur event_id.
  • price.apply et price.revert ne sont envoyés qu'une seule fois : si la livraison échoue, l'action passe en failed. Dédoublonnez sur action_id.
  • briefing.ready est envoyé une fois par jour.

Confirmer un prix que vous avez appliqué

  • Un price.apply n'est pas considéré comme appliqué tant que votre système ne le dit pas. Après avoir modifié le prix dans votre boutique, appelez POST /actions/{action_id}/confirm avec votre clé API : l'action passe de « envoyée » à « appliquée ».
  • Confirmer deux fois est sans danger — une action déjà appliquée est renvoyée telle quelle.
bash
curl -X POST https://4pricing.net/api/v1/pricing/actions/ACTION_ID/confirm \
  -H "X-API-Key: COLLEZ_VOTRE_CLE_ICI"

Exemples de corps

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/…"
}

Erreurs

Les erreurs arrivent avec le bon statut HTTP et un corps JSON {"detail": …}. detail est un texte, un objet avec un code que votre programme peut traiter, ou — pour 422 — la liste des champs invalides.

StatutCodeSignification
401—La clé API est manquante, erronée ou révoquée.
402plan_requiredLe compte n'a pas d'abonnement 4pricing actif.
402plan_limitUne limite du forfait serait dépassée (URL surveillées, boutiques concurrentes) ou une actualisation est arrivée avant l'intervalle minimal. Le message indique laquelle.
402insufficient_creditsPas assez de crédits pour un appel qui lit une page de boutique. Rien n'a été lu ni facturé.
403—Bloqué par le pare-feu avant d'atteindre l'API — en général un User-Agent générique comme Python-urllib. Envoyez votre propre User-Agent.
404—La ressource n'existe pas, n'appartient pas à votre compte, ou le chemin n'est pas disponible via l'API.
409recommendation_moved · own_from_listing · invalid_state · webhook_secret_requiredConflit : le prix recommandé a changé (recommendation_moved), l'action est dans un autre état (invalid_state), un secret de webhook est requis, ou l'opération ne s'applique pas à cet élément.
422—Données invalides, par exemple une URL sans http/https ou un champ obligatoire manquant. detail liste les champs.
429—Plus de 60 requêtes par minute pour le compte (ou trop de clés invalides). Attendez Retry-After secondes.
503credit_wallet_unavailableLe portefeuille de crédits est momentanément illisible. Réessayez plus tard ; rien n'a été facturé.

Corps d'erreur

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

Exemples de code

La même lecture dans quatre langages, avec une pause suivie d'une nouvelle tentative sur 429, puis l'envoi des ventes. Remplacez COLLEZ_VOTRE_CLE_ICI par votre clé (ou définissez la variable d'environnement PRICING_API_KEY).

Node.js : lire vos produits comparés

javascript
// Node.js 18+ (fetch is built in, no package needed)
const API_KEY = process.env.PRICING_API_KEY; // COLLEZ_VOTRE_CLE_ICI
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) {
      // Plus de 60 requêtes/minute : attendez le nombre de secondes indiqué par Retry-After, puis réessayez
      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() {
  // Vos produits comparés : votre prix, le concurrent le moins cher, le verdict
  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 : lire vos produits comparés

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"]  # COLLEZ_VOTRE_CLE_ICI
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",
            # Définissez votre propre User-Agent : celui par défaut de certaines bibliothèques HTTP (Python urllib) est bloqué avec un 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:
                # Plus de 60 requêtes/minute : attendez le nombre de secondes indiqué par Retry-After, puis réessayez
                time.sleep(int(err.headers.get("Retry-After", "60")))
                continue
            raise
    raise RuntimeError("rate limited")


# Vos produits comparés : votre prix, le concurrent le moins cher, le verdict
for g in call("/groups/"):
    print(g["name"], g["own_price_cents_effective"], g["min_competitor_cents"], g["verdict"])

curl : envoyer vos ventes quotidiennes

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

PHP : envoyer vos ventes quotidiennes

php
<?php
$apiKey = 'COLLEZ_VOTRE_CLE_ICI';

// Ventes quotidiennes par produit (par sku ou group_id), jusqu'à 2 000 lignes par requête
$rows = [
    ['sku' => 'TSHIRT-BLANC-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": []}

Questions fréquentes

Faut-il être programmeur pour utiliser l'API 4pricing ?

Non. L'intégration rapide vous fournit un fichier PHP prêt à l'emploi : vous créez une clé dans le panneau, vous la collez dans le fichier, vous déposez le fichier sur votre hébergement et vous l'ouvrez dans le navigateur. Pour des intégrations plus poussées (un ERP, une plateforme de boutique), un développeur peut s'appuyer sur la référence des endpoints et la spécification OpenAPI.

Combien coûte l'API 4pricing ?

L'API est incluse dans tous les abonnements 4pricing, avec les mêmes limites que le panneau. La lecture de vos données est gratuite ; seuls les appels qui lisent une page de boutique (ajout d'une nouvelle URL, actualisation, recherche en direct, recherche de concurrents) consomment des crédits, comme dans le panneau.

Quels appels consomment des crédits ?

POST /products/, POST /products/{product_id}/refresh, POST /groups/{group_id}/refresh, POST /groups/{group_id}/members avec une nouvelle URL, POST /groups/{group_id}/suggestions et POST /search/. Si le solde est insuffisant, vous recevez 402 insufficient_credits et rien n'est lu.

Les prix que j'envoie via l'API comptent-ils dans la limite d'URL de mon forfait ?

Non. Seules comptent les adresses que 4pricing lit sur une page — vos propres pages produit et chaque page concurrente séparément. Les prix envoyés avec POST /own-products/ ou /own-products/bulk ne comptent ni comme URL ni comme crédits.

Puis-je limiter ce à quoi une clé a accès ?

Non, il n'y a pas de portées : une clé voit et peut modifier tout votre compte 4pricing. Utilisez une clé distincte pour chaque intégration et révoquez toute clé que vous n'utilisez plus ; la révocation est effective immédiatement.

Que se passe-t-il si j'envoie plus de 60 requêtes par minute ?

Vous recevez 429 avec un en-tête Retry-After. La limite s'applique par compte et est partagée par toutes vos clés. Attendez le nombre de secondes indiqué dans Retry-After et réessayez ; pour de nombreux produits, utilisez les appels en masse (jusqu'à 2 000 lignes par requête).

Comment faire arriver automatiquement le prix recommandé dans ma boutique ?

Liez le groupe à votre boutique avec store_kind = webhook, définissez une adresse et un secret de webhook, et traitez l'événement price.apply : modifiez le prix dans votre boutique, puis appelez POST /actions/{action_id}/confirm. L'approbation d'un changement de prix reste une décision prise dans le panneau.

Existe-t-il un SDK ou un plugin prêt à l'emploi ?

Il n'existe ni SDK ni plugin officiel. L'API est du REST simple avec JSON, donc tout langage capable d'envoyer des requêtes HTTPS convient ; la spécification OpenAPI peut être chargée dans des outils qui génèrent un client automatiquement.