Products Manager APP

API Reference

Errors

L'API Products Manager retourne des erreurs structurées et prévisibles. Chaque réponse d'erreur suit un format JSON uniforme quel que soit l'endpoint ou le type de problème.


Format d'une Réponse d'Erreur

Toutes les erreurs retournent un objet JSON avec la structure suivante :

{
  "error": {
    "code": "PRODUCT_NOT_FOUND",
    "message": "The requested product does not exist.",
    "details": {
      "product_id": 9999
    }
  }
}
ChampTypeDescription
error.codestringCode d'erreur applicatif, stable et lisible par machine
error.messagestringMessage lisible par l'humain, en anglais
error.detailsobjectInformations contextuelles supplémentaires (optionnel)

Le champ details peut contenir des champs spécifiques selon l'erreur : identifiant de la ressource introuvable, champs en échec de validation, délai d'attente avant retry, etc.


Codes HTTP Utilisés

Code HTTPSignificationCauses typiques
400 Bad RequestRequête malforméeBody JSON invalide, paramètre manquant ou de mauvais type
401 UnauthorizedNon authentifiéToken absent, expiré ou révoqué
403 ForbiddenAccès refuséPermission insuffisante, quota dépassé, tenant non autorisé
404 Not FoundRessource introuvableID inexistant ou appartenant à un autre tenant
409 ConflictConflit de ressourceSKU déjà existant, import déjà en cours
422 Unprocessable EntityErreur de validationDonnées structurellement valides mais métier invalides (EAN incorrect, champ obligatoire vide)
429 Too Many RequestsRate limit dépasséTrop de requêtes dans la fenêtre de temps
500 Internal Server ErrorErreur serveurErreur inattendue côté backend
503 Service UnavailableService indisponibleMaintenance, surcharge, provider IA inaccessible

Codes d'Erreur Applicatifs

Authentification

CodeHTTPDescription
AUTH_TOKEN_EXPIRED401Le JWT access token a expiré — utiliser /auth/refresh
AUTH_TOKEN_INVALID401Token malformé ou signature invalide
AUTH_TOKEN_REVOKED401Token révoqué manuellement (déconnexion, rotation)
AUTH_INVALID_CREDENTIALS401Email ou mot de passe incorrect
AUTH_ACCOUNT_DISABLED401Compte utilisateur désactivé par un admin
AUTH_INSUFFICIENT_PERMISSIONS403L'utilisateur n'a pas la permission requise pour cette action
AUTH_API_KEY_INVALID401API Key absente, invalide ou révoquée
AUTH_API_KEY_SCOPE_DENIED403L'API Key n'a pas le scope requis pour cet endpoint

Validation

CodeHTTPDescription
VALIDATION_ERROR422Erreur de validation générique — voir details.fields
INVALID_EAN422Code EAN/GTIN invalide (checksum ou longueur incorrecte)
INVALID_SKU_FORMAT422Format de SKU non conforme aux règles du tenant
DUPLICATE_SKU409Un produit avec ce SKU existe déjà dans le catalogue
DUPLICATE_EAN409Un produit avec cet EAN existe déjà
REQUIRED_FIELD_MISSING422Champ obligatoire absent dans le body
INVALID_DATE_FORMAT422Date non conforme au format ISO 8601
FILE_TOO_LARGE400Fichier uploadé dépasse la limite autorisée
UNSUPPORTED_FILE_FORMAT400Format de fichier non supporté pour cet endpoint

Quotas Multi-tenant

CodeHTTPDescription
QUOTA_PRODUCTS_EXCEEDED403Le nombre maximum de produits du plan est atteint
QUOTA_IMPORTS_EXCEEDED403Le quota mensuel d'imports est épuisé
QUOTA_EXPORTS_EXCEEDED403Le quota mensuel d'exports est épuisé
QUOTA_CREDITS_EXHAUSTED403Les crédits IA du tenant sont épuisés
QUOTA_CONNECTORS_EXCEEDED403Le nombre maximum de connecteurs actifs est atteint
QUOTA_USERS_EXCEEDED403La limite d'utilisateurs du plan est atteinte
PLAN_FEATURE_UNAVAILABLE403La fonctionnalité n'est pas incluse dans le plan actuel

Ressources Introuvables

CodeHTTPDescription
PRODUCT_NOT_FOUND404Produit introuvable pour l'ID fourni
SUPPLIER_NOT_FOUND404Fournisseur introuvable
IMPORT_NOT_FOUND404Session d'import introuvable
EXPORT_NOT_FOUND404Export introuvable
CONNECTOR_NOT_FOUND404Connecteur introuvable
TENANT_NOT_FOUND404Tenant introuvable ou accès non autorisé
USER_NOT_FOUND404Utilisateur introuvable
MEDIA_NOT_FOUND404Fichier média introuvable

Logique Métier

CodeHTTPDescription
IMPORT_ALREADY_RUNNING409Un import est déjà en cours pour ce fournisseur
IMPORT_INVALID_MAPPING422Le mapping de colonnes ne correspond pas au fichier
ENRICHMENT_PROVIDER_UNAVAILABLE503Le provider d'IA sélectionné est temporairement indisponible
ENRICHMENT_JOB_NOT_FOUND404Job d'enrichissement introuvable
CONNECTOR_AUTH_FAILED422Échec d'authentification auprès de la plateforme externe
CONNECTOR_SYNC_IN_PROGRESS409Une synchronisation est déjà en cours sur ce connecteur
PRICE_MONITOR_NO_COMPETITORS422Aucun concurrent configuré pour ce produit
COMPLIANCE_MISSING_SUBSTANCES422Données substances manquantes pour générer la fiche REACH

Rate Limiting

CodeHTTPDescription
RATE_LIMIT_EXCEEDED429Limite de requêtes dépassée — voir header Retry-After

Exemples de Réponses d'Erreur

401 — Token expiré

{
  "error": {
    "code": "AUTH_TOKEN_EXPIRED",
    "message": "Access token has expired. Please refresh your token.",
    "details": {
      "expired_at": "2025-11-15T12:00:00Z"
    }
  }
}

403 — Permission insuffisante

{
  "error": {
    "code": "AUTH_INSUFFICIENT_PERMISSIONS",
    "message": "You do not have permission to perform this action.",
    "details": {
      "required_permission": "products:delete",
      "user_role": "viewer"
    }
  }
}

422 — Erreur de validation (champs multiples)

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "One or more fields failed validation.",
    "details": {
      "fields": {
        "ean": "Invalid EAN-13 checksum.",
        "price": "Must be a positive number.",
        "name": "This field is required."
      }
    }
  }
}

409 — SKU dupliqué

{
  "error": {
    "code": "DUPLICATE_SKU",
    "message": "A product with SKU 'PROD-001' already exists in this catalog.",
    "details": {
      "sku": "PROD-001",
      "existing_product_id": 4821
    }
  }
}

403 — Quota dépassé

{
  "error": {
    "code": "QUOTA_PRODUCTS_EXCEEDED",
    "message": "Your plan allows a maximum of 10,000 products. Upgrade your plan to add more.",
    "details": {
      "current_count": 10000,
      "plan_limit": 10000,
      "plan": "starter",
      "upgrade_url": "https://productsmanager.app/billing/upgrade"
    }
  }
}

429 — Rate limit

{
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Too many requests. Please wait before retrying.",
    "details": {
      "retry_after_seconds": 37,
      "limit": "100 requests per minute",
      "reset_at": "2025-11-15T10:31:00Z"
    }
  }
}

503 — Provider IA indisponible

{
  "error": {
    "code": "ENRICHMENT_PROVIDER_UNAVAILABLE",
    "message": "The AI enrichment provider is temporarily unavailable. Please retry in a few minutes.",
    "details": {
      "provider": "openai",
      "retry_after_seconds": 120
    }
  }
}

Gestion des Erreurs côté Client

Stratégie générale

  • 4xx : erreurs client — corriger la requête avant de réessayer (sauf 429)
  • 429 : attendre la durée indiquée dans Retry-After avant de réessayer
  • 5xx : erreurs serveur — réessayer avec backoff exponentiel

Retry avec Backoff Exponentiel (429 et 503)

Pour les erreurs 429 Too Many Requests et 503 Service Unavailable, implémentez un backoff exponentiel avec jitter :

import time
import random

def request_with_backoff(fn, max_retries=5):
    for attempt in range(max_retries):
        response = fn()
        if response.status_code not in (429, 503):
            return response
        retry_after = int(response.headers.get("Retry-After", 2 ** attempt))
        jitter = random.uniform(0, 1)
        wait = retry_after + jitter
        time.sleep(wait)
    raise Exception("Max retries exceeded")

Idempotency Keys

Pour les opérations qui créent ou modifient des ressources (POST, PATCH), utilisez le header Idempotency-Key avec un UUID unique par tentative logique. Si la requête est rejouée avec la même clé dans les 24 heures, l'API retourne la réponse originale sans re-exécuter l'opération :

curl -X POST "https://api.productsmanager.app/api/v1/imports" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
  -H "Content-Type: application/json" \
  -d '{"supplier_id": 42, "file_url": "https://..."}'

Ceci est particulièrement utile pour les imports et les créations en masse afin d'éviter les doublons en cas de timeout réseau ou d'erreur transitoire.


Documentation Associée