Documentation J+SERVICES Guides Référence API

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) :

⚠️ 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


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)

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

  1. Au besoin, GET /router/hotspot-profiles?force=true pour lire les profils réels.
  2. L’utilisateur ajuste (prix, libellé, masquer/afficher).
  3. POST /store/profiles/sync avec la liste complète des profils gérés.
  4. Effet immédiat : le catalogue public (/store/:slug) et le réapprovisionnement de stock respectent exclusions + overrides.

Notes techniques (côté backend, pour info)