Contrat API — Gestion des profils de vente TiketMOMO (app mobile)
Version : 1.0 — 2026-06-23 Backend : jservices-api (déployé) Pour : équipe app mobile MikhmoAI
But
Permettre au manager, depuis l’app mobile, de piloter ce qu’il vend sans attendre la synchronisation automatique depuis le routeur (cron toutes les 30 min) :
- mettre à jour un profil (prix, libellé, limites) ;
- forcer une synchro / vérifier l’écart avec le routeur ;
- retirer un profil de la vente (le cacher) ou le réactiver.
⚠️ Changement important : avant cette version, l’endpoint de sync écrivait dans un champ que rien ne lisait → aucun effet réel sur la vente. C’est désormais effectif : ce que l’app envoie est respecté par le catalogue acheteur ET par le moteur de stock (plus de re-création de stock pour un profil caché).
Généralités
- Base URL :
https://live.mikhmoai.com(équivalents :https://live.jmoai.net,https://tpay.mikhmoai.com). ⚠️api.jmoai.net/api.mikhmoai.comne routent PAS ces endpoints. - Auth : header
Authorization: Bearer <accessToken>(compte client lié à un manager). - Content-Type :
application/json. - Préfixe :
/api/v1/clients(alias legacy/api/v1/client).
1. Lister les profils de vente courants
GET /api/v1/clients/store/profiles
Réponse 200
{
"success": true,
"data": [
{ "name": "500F-7d-10G", "price": 500, "data_limit": "10G", "time_limit": "7d", "validity": null, "is_active": true }
]
}
data reflète la dernière liste poussée par l’app (vide si jamais synchronisé).
2. Synchroniser / mettre à jour / retirer des profils ⭐ endpoint principal
POST /api/v1/clients/store/profiles/sync
Corps
{
"nas_id": "HM40BD8YVTG",
"profiles": [
{ "name": "500F-7d-10G", "price": 500, "data_limit": "10G", "time_limit": "7d", "is_active": true },
{ "name": "1000F-30d-50G","price": 1200, "data_limit": "50G", "time_limit": "30d", "display_name": "Pack Pro", "is_active": true },
{ "name": "200F-1d", "is_active": false },
{ "name": "ancien-profil", "action": "delete" }
],
"metadata": { "source": "mobile", "app_version": "x.y.z" }
}
Champs par profil
| Champ | Type | Rôle |
|---|---|---|
name |
string (requis) | Nom EXACT du profil hotspot (clé d’identité, ex. 500F-7d-10G). |
price |
number | Prix de vente (override le prix dérivé du nom/config). |
data_limit |
string | Limite data affichée (ex. 10G). |
time_limit |
string | Durée (ex. 7d). |
validity |
string | Validité éventuelle. |
display_name |
string | Libellé affiché à l’acheteur (sinon = name). |
is_active |
bool | false = retiré de la vente (caché du catalogue + non réapprovisionné). Défaut true. |
action |
string | "delete" = oublie l’entrée (le profil redevient auto-détecté depuis le routeur s’il y existe). |
Sémantique à retenir (important pour l’UX)
- Cacher de la vente = renvoyer le profil avec
is_active: false. Il reste connu mais invisible aux acheteurs et non réapprovisionné en stock. - Réafficher = renvoyer le même profil avec
is_active: true. action: "delete"= supprime l’override côté boutique. ⚠️ Ce n’est PAS « retirer de la vente » : si le profil existe encore physiquement sur le routeur, il sera de nouveau auto-détecté et vendable au prochain cycle. Pour vraiment le masquer, utiliseris_active:false.- L’envoi est une réconciliation : seuls les profils présents dans
profilessont touchés (upsert/suppression). Les autres entrées existantes sont conservées.
Réponse 200
{
"success": true,
"message": "Profils de la boutique mis à jour avec la source de vérité locale.",
"updated_count": 2,
"deleted_count": 1
}
Erreurs : 400 { success:false, error } si profiles n’est pas un tableau.
3. Vérifier les profils RÉELS du routeur (contrôle d’écart)
GET /api/v1/clients/router/hotspot-profiles?force=true&allocation_id=<optionnel>
Lit les profils en direct depuis le routeur (sans force=true : dernier état connu
côté backend). À utiliser pour comparer ce qui est sur le routeur vs ce que le manager vend,
et proposer une synchro.
Réponse 200
{ "success": true, "result": [ { "name": "500F-7d-10G", "rate-limit": "…", "...": "…" } ] }
4. Config boutique (branding, prix, libellés avancés)
GET /api/v1/clients/store-config
PUT /api/v1/clients/store-config
PATCH /api/v1/clients/store-config
Gère store_settings.portal_editor (branding, plans détaillés, paiement) + display_name,
logo_url, store_slug. Complémentaire au point 2 : utiliser le point 2 pour le pilotage
rapide des profils de vente, le point 4 pour la config riche de la boutique.
Flux recommandé côté app
- Au besoin,
GET /router/hotspot-profiles?force=truepour lire les profils réels. - L’utilisateur ajuste (prix, libellé, masquer/afficher).
POST /store/profiles/syncavec la liste complète des profils gérés.- Effet immédiat : le catalogue public (
/store/:slug) et le réapprovisionnement de stock respectent exclusions + overrides.
Notes techniques (côté backend, pour info)
- Le contrôle est stocké dans
store_settings.sales_profileset lu pargetPublicStoreData(catalogue) etresolveEffectivePlans(auto-stock). - Le nom du profil reste la source de vérité des limites réelles appliquées sur le routeur
(ex.
500F-7d-10G→ uptime 7d + data 10G), cf. création de voucher. - Profils internes nommés
!...ou*...ne sont jamais vendus (exclusion native).