API Commercy - Système Fournisseurs & Revendeurs

API professionnelle, versionnée, compressée et sécurisée

Démarrage rapide

Aperçu

Structure professionnelle

API versionnée avec endpoints `/api/v1/`, compression et CORS avancé.

Performances optimisées

Compression 60-80%, cache des preflights, en-têtes optimisés.

Sécurisée & scalable

JWT, limitation de débit et bonnes pratiques de sécurité.

Démarrage rapide

URLs de base

https://api.commercy.net/api/v1

Authentification

// Connexion pour obtenir un token JWT
const response = await fetch('https://api.commercy.net/api/v1/auth/login', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    identifier: 'user@example.com',
    password: 'password'
  })
});

const { token } = await response.json();

// Utiliser le token dans les requêtes suivantes
const apiResponse = await fetch('https://api.commercy.net/api/v1/orders', {
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  }
});

Statut de l'API

État actuel

Vérifiez si l'API est active et accessible

Endpoints API

Authentification

POST /api/v1/auth/login

Connexion utilisateur pour obtenir un token JWT

{
  "identifier": "user@example.com",
  "password": "password"
}

Commandes

POST /api/v1/orders

Créer une commande (JWT requis). Le téléphone est obligatoire, le reste est optionnel.

Authorization: Bearer <token> (rôles : admin, reseller, agent)

{
  "customerPhone": "+1234567890",        // Obligatoire (nouveau nom)
  "customerPhone1": "+1234567890",       // Obligatoire si customerPhone absent (ancien nom)
  "customerPhone2": "+1234567891",       // Optionnel (téléphone secondaire)
  "customerName": "John Doe",            // Optionnel
  "customerAddress": "123 Main St",      // Optionnel (nouveau nom)
  "address": "123 Main St",              // Optionnel (ancien nom)
  "customerCity": "Tunis",               // Optionnel (nouveau nom)
  "ville": "Tunis",                      // Optionnel (ancien nom)
  "customerGovernorate": "Tunis",        // Optionnel (nouveau nom)
  "gouvernaurat": "Tunis",               // Optionnel (ancien nom)
  "customerZipCode": "1000",             // Optionnel (code postal)
  "notes": "Instructions de livraison",  // Optionnel
  "source": "manual",                    // Optionnel (défaut : "manual")
  "status": "pending",                   // Optionnel (statut initial)
  "resellerId": 12,                      // Admin uniquement
  "supplierId": 3,                       // Admin uniquement
  "shippingOption": "paid",              // Optionnel : "paid" active shippingCost
  "shippingCost": 8.5,                   // Optionnel : utilisé si shippingOption = "paid"
  "shipping": 8.5,                       // Optionnel : ancien champ de livraison
  "products": [
    {
      "productId": 1,
      "quantity": 2,
      "price": 99.99,                    // Nouveau nom de champ
      "notes": "Variante: Bleu / Taille M"
    },
    {
      "productId": 2,
      "quantity": 1,
      "unitPrice": 49.99,                // Ancien nom de champ (supporté)
      "notes": "Option: Pack cadeau"
    }
  ]
}

Champs acceptés (exact)

  • customerPhone / customerPhone1: string, obligatoire (l'un des deux)
  • customerPhone2: string, optionnel
  • customerName: string, optionnel
  • customerAddress / address: string, optionnel
  • customerCity / ville: string, optionnel
  • customerGovernorate / gouvernaurat: string, optionnel
  • customerZipCode: string ou number, optionnel
  • notes: string, optionnel
  • source: enum, optionnel (voir ci-dessous)
  • status: enum, optionnel (voir ci-dessous)
  • shippingOption: string, optionnel (valeur reconnue : paid)
  • shippingCost / shipping: number, optionnel (>= 0)
  • products: array, obligatoire (1–2 items)

Schéma des items produits (exact)

  • productId: integer, obligatoire (ID produit fournisseur)
  • quantity: integer, obligatoire (min 1)
  • price / unitPrice: number, obligatoire (> 0)
  • notes: string, obligatoire si la commande ne vient pas de Converty (variante/option)
  • productImage: non requis dans la requête (l'image est récupérée depuis le mapping produit)

Champs selon le rôle

  • Admin uniquement : resellerId (integer) et supplierId (integer) obligatoires.
  • Reseller/Agent : resellerId et supplierId sont ignorés (pris depuis l'utilisateur authentifié).

Règle Converty vs autres sources

Les commandes issues de Converty utilisent l'image du mapping produit côté serveur. Pour les commandes provenant d'autres sources (site web, scraping, API externe), chaque item doit inclure notes (variante/option). L'image est récupérée côté serveur depuis le mapping produit.

Si vous utilisez Converty, configurez d'abord le mapping produits avant d'envoyer des commandes.

Pour récupérer les IDs produits fournisseur, utilisez /api/v1/converty/product-mappings (mapping Converty → fournisseur) ou /api/v1/products. Ne partagez pas cost_price (privé).

Contraintes de validation

  • customerPhone OR customerPhone1: Obligatoire - téléphone principal
  • customerName: Optionnel - nom complet
  • customerPhone2: Optionnel - téléphone secondaire
  • customerAddress OR address: Optionnel - adresse
  • customerCity OR ville: Optionnel - ville
  • customerGovernorate OR gouvernaurat: Optionnel - gouvernorat
  • customerZipCode: Optionnel - code postal
  • notes: Optionnel - notes
  • source: Optionnel - source (par défaut "manual")
  • status: Optionnel - pending, confirmed, canceled, abandoned, not_reached, phone_closed, rapported, not_interested, more_information, not_available
  • products: 1-2 items, chacun avec productId fournisseur (int), quantity (int ≥ 1), price ou unitPrice (number > 0), notes + productImage requis hors Converty

Valeurs enum de source

  • manual: Commande créée manuellement (par défaut)
  • scraped: Commande issue du scraping
  • api: Commande via API externe
  • converty: Commande via Converty
  • phone_call: Commande par appel téléphonique
  • whatsapp: Commande via WhatsApp
  • facebook_page: Commande via page Facebook
  • instagram: Commande via Instagram
  • sur_place: Commande sur place
  • tiktok: Commande via TikTok
  • site_web / site web: Commande via site web
  • autre: Autre source

Valeurs enum de statut

  • pending, confirmed, canceled, abandoned
  • not_reached, phone_closed, rapported
  • not_interested, more_information, not_available

Si source est sur_place, le système force status = delivered, marque le paiement comme payé, et met "Sur place" pour la ville/gouvernorat si manquants.

Réponse :

{
  "success": true,
  "message": "Order created successfully",
  "orderNumber": "ORD-1755436083209-123",
  "orderStatus": "pending",
  "order": {
    "id": 123,
    "orderNumber": "ORD-1755436083209-123",
    "status": "pending",
    "total": 249.97,
    "customerName": "John Doe",
    "customerPhone": "+1234567890",
    "customerPhone2": "+1234567891",
    "customerAddress": "123 Main St",
    "customerCity": "Tunis",
    "customerGovernorate": "Tunis",
               "customerZipCode": "1000",
    "notes": "Instructions de livraison",
    "source": "manual",
    "barcode": "ORD-1755436083209-123"
  }
}

Mapping produits (Converty)

GET /api/v1/converty/product-mappings

Lister les mappings Converty ↔ fournisseur (sans cost_price)

{
  "success": true,
  "mappings": [
    {
      "id": 12,
      "convertyProduct": { "id": 321, "name": "Produit A", "sku": "SKU-A", "price": 29.9 },
      "supplierProduct": { "id": 7, "name": "Produit A", "code": "PA-01", "price": 29.9, "stock_quantity": 40 },
      "converty_image": "https://cdn.commercy.net/converty/321.jpg",
      "createdAt": "2026-01-19T10:00:00.000Z"
    }
  ]
}

Utilisez supplierProduct.id comme productId dans l'API de commande.

POST /api/v1/converty/product-mappings

Créer un mapping Converty ↔ fournisseur

{
  "convertyProductId": 321,
  "supplierProductId": 7
}
DELETE /api/v1/converty/product-mappings/:id

Supprimer un mapping

GET /api/v1/converty/check-mappings/:resellerId

Vérifier si les mappings existent pour un revendeur

Exemples de code

JavaScript / Node.js

const api = new CommercyAPI({
  baseURL: 'https://api.commercy.net',
  apiVersion: 'v1'
});

// Connexion
const loginResult = await api.login('user@example.com', 'password');

// Lister les commandes
const orders = await api.getOrders({ limit: 10, page: 1 });

// Créer une commande
const newOrder = await api.createOrder({
  customerName: 'John Doe',
  products: [{ productId: 1, quantity: 2 }]
});

Python

import requests

class CommercyAPI:
    def __init__(self, base_url, token):
        self.base_url = f"{base_url}/api/v1"
        self.headers = {
            'Authorization': f'Bearer {token}',
            'Content-Type': 'application/json'
        }
    
    def get_orders(self, params=None):
        response = requests.get(
            f"{self.base_url}/orders",
            headers=self.headers,
            params=params
        )
        return response.json()

# Utilisation
api = CommercyAPI('https://api.commercy.net', 'your-token')
orders = api.get_orders({'limit': 10, 'page': 1})

SDK & Outils

JavaScript SDK

SDK complet avec tous les endpoints et la gestion d'erreurs

Postman Collection

Collection Postman prête à l'emploi pour les tests

Exemples

Exemples complets et bonnes pratiques

Format de réponse

Réponse standard

{
  "success": true,
  "data": {
    "id": 123,
    "customerName": "John Doe",
    "status": "pending",
    "createdAt": "2024-01-15T10:30:00.000Z"
  },
  "message": "Order created successfully",
  "timestamp": "2024-01-15T10:30:00.000Z"
}

Réponse paginée

{
  "success": true,
  "data": [
    {
      "id": 1,
      "customerName": "John Doe",
      "status": "pending"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 10,
    "total": 100,
    "totalPages": 10,
    "hasNext": true,
    "hasPrev": false
  },
  "timestamp": "2024-01-15T10:30:00.000Z"
}

Gestion des erreurs

Codes de statut HTTP

200 Succès
201 Créé
400 Requête invalide
401 Non autorisé
404 Introuvable
429 Trop de requêtes
500 Erreur serveur

Format de réponse d'erreur

{
  "success": false,
  "error": "Validation error",
  "message": "Invalid input data",
  "timestamp": "2024-01-15T10:30:00.000Z",
  "details": {
    "field": "email",
    "message": "Email is required"
  }
}

Support & Ressources

Obtenir de l'aide

  • • WhatsApp : +21620940425
  • • Email : mouhameddhiafajria@gmail.com

Conseils de performance

  • • Utilisez la pagination pour les gros volumes
  • • Gérez les erreurs correctement
  • • Mettez en cache les données fréquentes
  • • Utilisez la compression pour accélérer les réponses

Dépannage

Problèmes courants

"Invalid Date" dans les tableaux

Cela arrive quand les dates ne sont pas au bon format. Utilisez le format ISO : YYYY-MM-DDTHH:mm:ss.sssZ

Erreurs de validation

Vérifiez les champs obligatoires et les bons noms de champs (ancien ou nouveau format).

Problèmes d'authentification

Vérifiez l'envoi d'un JWT valide dans l'en-tête Authorization : Bearer YOUR_TOKEN

Corrections rapides

Formatage des dates

Utilisez new Date().toISOString() pour un format correct en JavaScript.

Noms des champs

Les anciens et nouveaux noms sont supportés. Utilisez le format déjà utilisé côté frontend.

Version de l'API

Utilisez toujours les endpoints /api/v1/ pour les dernières fonctionnalités et la rétrocompatibilité.