Contrat API — offres de services des boutiques revendeur
Périmètre
Ce contrat sépare les offres propres au vendeur des licences MikhmoAI/JRadius :
GET /api/store/catalogreste le catalogue de licences existant.GET /api/store/services?ref=CODEexpose les services et expertises publiés dans une boutique.- La création et la publication demandent une session revendeur approuvé. Les offres sont modérées avant d’être visibles.
La publication et la découverte sont couvertes ici. Le prix fixe affiché est informatif : ce lot ne crée pas de commande ni de paiement pour une prestation. Le vendeur peut continuer à utiliser les liens de paiement Expert Hub existants, séparément. Le checkout du catalogue de licences reste inchangé.
Toutes les réponses utilisent application/json. Les routes vendeur acceptent une session partenaire par cookie ou un jeton Bearer dans Authorization.
1. Consulter les offres de sa boutique
GET /api/v1/partner/store/services?page=1&limit=50
Réservé à un revendeur approuvé. La pagination accepte page (défaut 1) et limit (1–100, défaut 50). Toutes les offres du vendeur sont renvoyées, y compris celles en brouillon et en modération.
{
"success": true,
"data": {
"items": [
{
"id": "uuid",
"offer_type": "EXPERTISE",
"category_code": "NETWORK",
"title": "Audit réseau MikroTik",
"summary": "Diagnostic et recommandations pour votre réseau.",
"description": "Description détaillée de la prestation.",
"pricing_mode": "FIXED",
"price_amount": 25000,
"currency": "XOF",
"service_area": "Cotonou et à distance",
"delivery_mode": "HYBRID",
"duration_minutes": 120,
"publication_status": "DRAFT",
"created_at": "2026-10-23T10:00:00.000Z",
"updated_at": "2026-10-23T10:00:00.000Z"
}
],
"page": 1,
"limit": 50,
"total": 1
}
}
2. Créer une offre
POST /api/v1/partner/store/services
Content-Type: application/json
{
"offer_type": "SERVICE",
"category_code": "NETWORK",
"title": "Installation Wi-Fi professionnelle",
"summary": "Installation et configuration sur site.",
"description": "Description précise du service et de ses limites.",
"pricing_mode": "FIXED",
"price_amount": 25000,
"currency": "XOF",
"service_area": "Cotonou",
"delivery_mode": "ON_SITE",
"duration_minutes": 180
}
Tous les champs sont requis à la création. offer_type vaut SERVICE ou EXPERTISE. category_code doit désigner une catégorie Expert Hub active. pricing_mode vaut FIXED ou QUOTE : en mode FIXED, price_amount est un entier XOF entre 100 et 2 000 000; en mode QUOTE, il doit être null. currency vaut actuellement XOF. delivery_mode vaut REMOTE, ON_SITE ou HYBRID. duration_minutes est nul ou compris entre 15 et 43 200.
Les champs de texte sont du texte brut; le client les affiche en échappant le HTML.
Réponse 201 : l’offre créée avec publication_status: "DRAFT". La création ne publie jamais l’offre directement.
3. Modifier, soumettre et suspendre
PATCH /api/v1/partner/store/services/{serviceId}
POST /api/v1/partner/store/services/{serviceId}/publish
POST /api/v1/partner/store/services/{serviceId}/pause
PATCH accepte un ou plusieurs champs de création. Si une offre ACTIVE est modifiée, elle passe à PENDING_REVIEW et disparaît de la boutique jusqu’à nouvelle approbation. Une offre déjà PENDING_REVIEW ne peut pas être modifiée. Les champs prix doivent rester cohérents avec pricing_mode.
POST .../publish soumet une offre en état DRAFT, REJECTED ou PAUSED à la modération. La réponse est 200 avec publication_status: "PENDING_REVIEW".
POST .../pause retire immédiatement une offre ACTIVE de la boutique. Une offre suspendue peut être soumise à nouveau. Le vendeur ne peut lire ni modifier l’offre d’un autre revendeur.
4. Lire le catalogue public de la boutique
GET /api/store/services?ref=CODE_REVENDEUR&page=1&limit=50
La route ne renvoie que les offres ACTIVE d’un revendeur dont la candidature est APPROVED et le compte ACTIVE. page commence à 1; limit vaut 1–100 (défaut 50). La réponse inclut page, limit et total. Une boutique valide sans offre publiée renvoie 200 et une liste vide avec total: 0.
{
"success": true,
"data": {
"store": { "code": "RESEAU-20", "name": "Services Réseau" },
"items": [
{
"id": "uuid",
"offer_type": "EXPERTISE",
"category_code": "NETWORK",
"title": "Audit réseau MikroTik",
"summary": "Diagnostic et recommandations pour votre réseau.",
"description": "Description détaillée de la prestation.",
"pricing_mode": "QUOTE",
"price_amount": null,
"currency": "XOF",
"service_area": "À distance",
"delivery_mode": "REMOTE",
"duration_minutes": null,
"publication_status": "ACTIVE"
}
]
}
}
Les données personnelles du vendeur et les notes de modération ne sont jamais exposées par cette route.
5. Modération (API d’administration)
GET /api/admin/api/partners/store-services/review-queue?page=1&limit=50
POST /api/admin/api/partners/store-services/{serviceId}/review
Le premier endpoint est réservé à un administrateur authentifié. Le second accepte :
{ "decision": "APPROVE" }
ou :
{ "decision": "REJECT", "review_notes": "Ajoutez une description du périmètre livré." }
Une approbation n’est possible que si le vendeur est toujours approuvé. Un rejet exige un motif d’au moins 5 caractères. Les offres ne peuvent pas être approuvées deux fois ni modérées hors de l’état PENDING_REVIEW.
États et erreurs métier
États : DRAFT, PENDING_REVIEW, ACTIVE, PAUSED, REJECTED.
| Code | HTTP | Sens |
|---|---|---|
RESELLER_NOT_APPROVED |
403 | Le vendeur doit être approuvé pour gérer ou publier des offres. |
RESELLER_CODE_REQUIRED |
400 | Le paramètre ref est absent. |
RESELLER_NOT_FOUND |
404 | La boutique est inconnue, suspendue ou non approuvée. |
SERVICE_CATEGORY_INVALID |
400 | La catégorie n’est pas active dans l’Expert Hub. |
STORE_SERVICE_NOT_FOUND |
404 | L’offre n’existe pas ou n’appartient pas au vendeur. |
STORE_SERVICE_REVIEW_PENDING |
409 | L’offre ne peut pas être modifiée pendant la modération. |
STORE_SERVICE_STATE_INVALID |
409 | L’action ne correspond pas à l’état actuel de l’offre. |
STORE_SERVICE_PRICE_INVALID |
400 | Le prix ne correspond pas au mode FIXED/QUOTE. |
Les erreurs de validation Joi utilisent VALIDATION_ERROR.
Garanties et limites
- Le serveur impose l’identité du propriétaire à partir du jeton;
reseller_idn’est jamais accepté du client. - Une offre n’est visible publiquement qu’après approbation administrative; une modification d’offre active la remet en modération.
- Le catalogue de licences existant conserve son schéma et son parcours de checkout.
- Le prix fixe publié ne vaut pas confirmation d’achat et ne crée ni transaction, ni commission, ni livraison de service.
- La mise en ligne de prestations n’active pas de fonctions Provider Stack et ne change pas le périmètre commercial du pilote WireGuard.