Contrat API — Technicien licences
Base : https://live.jmoai.net · enveloppe : { success, data, error? }.
Authentification technicien : cookie partner_token ou Authorization: Bearer <jwt partenaire>.
Les routes /api/v1/resellers/* exigent un revendeur approuvé.
Parcours A — générer puis activer ou envoyer une clé
1. Voir le solde, le stock et les prix
GET /api/v1/resellers/inventory
Réponse : balance, currency, catalog_prices, price_tiers, available_licenses.
Chaque entrée de stock contient désormais les clés du technicien uniquement :
{
"id": "mikhmoai:vpn-6m",
"product_code": "mikhmoai",
"plan_code": "vpn-6m",
"quantity": 1,
"total_quantity": 2,
"license_ids": ["code_1", "code_2"],
"license_keys": ["JPS-AAAA-BBBB-CCCC", "JPS-DDDD-EEEE-FFFF"],
"licenses": [
{ "id": "code_1", "license_key": "JPS-AAAA-BBBB-CCCC", "status": "AVAILABLE" },
{
"id": "code_2",
"license_key": "JPS-DDDD-EEEE-FFFF",
"status": "USED",
"assigned_to_manager_id": "mgr_123",
"activated_at": "2026-10-08T10:00:00Z"
}
]
}
quantity compte les clés encore disponibles ; total_quantity inclut l’historique du stock
du technicien. Une clé consommée reste visible avec son statut, mais ne redevient pas stock.
2. Obtenir un devis exact
GET /api/v1/resellers/licenses/quote?plan_code=vpn-6m&quantity=5
Réponse : retail_price, unit_price, quantity, total_amount, discount_pct,
tier_label, balance, balance_after, sufficient_funds.
Le devis réutilise le même calcul que POST /inventory/purchase : prix public du plan +
palier reseller_price_tiers. Aucun autre barème n’est appliqué.
3. Acheter du stock avec le portefeuille B2B
POST /api/v1/resellers/inventory/purchase
{ "plan_code": "vpn-6m", "quantity": 5 }
Réponse 201 : unit_price, total_amount, discount_pct, tier_label, balance,
license_ids, license_keys, licenses, transfer_id, purchase_reference.
Erreurs : PLAN_NOT_FOUND, QUANTITY_TOO_LARGE, WALLET_INSUFFICIENT_FUNDS, 429.
4. Envoyer la clé au client
Le client peut réclamer une clé AVAILABLE sur claim.jmoai.net via les routes existantes :
POST /api/v1/licenses/claim-guestavec{ "license_key": "...", "email": "client@example.com" }POST /api/v1/licenses/claimpour un client authentifiéGET /api/v1/licenses/claim-magicpour les liens signés existants
Pour les clés de stock technicien, la clé fait foi : le client saisi est créé/résolu, la
clé passe AVAILABLE → USED, la licence est activée, et le client est rattaché au
technicien qui avait généré la clé.
5. Activer pour un email client
POST /api/v1/resellers/inventory/activate-for-email
{ "license_id": "code_1", "client_email": "client@example.com" }
ou :
{ "license_key": "JPS-AAAA-BBBB-CCCC", "client_email": "client@example.com" }
La route réutilise le claim existant, ne duplique pas la logique d’activation, et refuse une clé hors stock du technicien.
Parcours B — lien de paiement technicien
POST /api/v1/resellers/payment-links
{ "plan_code": "vpn-6m", "client_email": "client@example.com" }
Réponse 201 :
{
"url": "https://live.jmoai.net/api/v1/payments/hub?productCode=mikhmoai&planCode=vpn-6m&promoCode=TECH-SAFEJO&referral_code=TECH-SAFEJO&partnerId=res_123&email=client%40example.com",
"plan": { "product_code": "mikhmoai", "plan_code": "vpn-6m", "name": "VPN 6 mois" },
"price": { "amount": 4000, "currency": "XOF" },
"commission_estimee": 640
}
Le client paie le prix public. Le lien ouvre le Hub existant ; le Hub relaie promoCode,
referral_code et partnerId vers POST /api/v1/licenses/prepare-payment. Le webhook de
paiement lit les alias existants avec lireCodeParrainage, enregistre la commission dans
partner_commissions, puis livre la licence. Si l’acheteur est invité, le rattachement CRM
est posé au moment où il réclame sa licence.
partnerId présent dans l’URL du Hub est une valeur non signée. Il sert uniquement au
mécanisme préexistant linkReferral pour rattacher le client au premier technicien qui
l’amène ; avec la règle de non-réattribution, le premier lien valide gagne.
Commissions visibles
Pour les commissions revendeur licences, la route à afficher est GET /api/v1/referral/me :
elle lit partner_commissions, renvoie earnings, total_referrals et recent_activity.
GET /api/v1/partner/paiement/commissions appartient à l’espace partenaire marchand
partners et décrit les commissions facturées sur ventes agrégateur ; ce n’est pas le
tableau principal des commissions de parrainage technicien.
Règles
- Prix public : toujours payé par le client sur le lien de paiement.
- Prix technicien : uniquement pour l’achat de stock via portefeuille B2B.
- Les clés exposées par
/inventorysont filtrées parcreated_by_partner_id. - Un client déjà rattaché à un autre technicien n’est pas réattribué ; la fiche CRM existante reste propriétaire.
- Les nouvelles routes d’action sont protégées par
actionLimiter.