Relancer les élèves inactifs
Chaque lundi, envoie un court message aux élèves sans séance terminée depuis 14 jours, avec un premier passage sans envoi.
Chaque lundi, les élèves sans séance terminée depuis 14 jours reçoivent un message dans l'app. Ce cas pratique écrit en ton nom : il demande une clé avec Élèves › Lire (students:read), Entraînement › Lire (training:read) et Messages › Écrire (messaging:write), et une offre qui inclut les écritures. Crée la clé dans l'app, conditions d'usage acceptées. L'API ne donne pas la connexion de l'élève : le cas pratique regarde les séances terminées. Un événement remplacera cette lecture régulière.
Ce que fait ce cas pratique
- Déclencheur : chaque lundi, puis
GET /mepourcoach.first_name, la signature. - Séances :
GET /workouts?status=done&since=<J-14>, toutes les pages (statusvautscheduled,done,in_progress,draftoumissed).sinceporte surupdated_at: on ne garde donc que lesstudent_iddes séances dontended_at, ouupdated_ats'il manque, est supérieur ou égal à J-14. - Élèves :
GET /students, toutes les pages. Chaque élève absent de cet ensemble reçoit un message, sauf s'il est arrivé il y a moins de 14 jours ou si son contrat estPAUSEDouEXPIRED. - Envoi : un
POST /operations/messaging.sendpar élève relancé.
curl -X POST https://api.fitdistance.io/api/partner/v1/operations/messaging.send \
-H "Authorization: Bearer fd_live_xxxxxxxx" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: inactif-42-2026-10-26" \
-d '{"text": "Salut Léa, …", "studentId": 42}'L'Idempotency-Key vaut inactif-<id>-<AAAA-MM-JJ>, avec la date du passage : un rejeu le même jour est remboursé. Voir Écritures et idempotence.
Le message
Salut Léa, je n'ai pas vu de séance terminée de ta part depuis deux semaines. Si quelque chose te gêne, écris-le-moi ici.
Mathias
Ce que ça coûte
Une page lue coûte un crédit, débité avant l'appel ; chaque message envoyé en coûte un. Cent élèves à trois séances par semaine : 600 séances en 14 jours, donc 14 pages lues avec limit=50, 4 avec limit=200, élèves compris, puis un message par élève relancé. À ce volume, les séances tiennent sur plus d'une page et le scénario Make s'arrête à chaque passage : passe par n8n ou par un script. Un paramètre refusé coûte quand même un crédit ; un 401, un 403 ou un 429 ne coûtent rien ; un rejeu est remboursé.
Un premier passage sans rien envoyer
messaging.send n'a pas d'aperçu avec studentId : dry_run: true donne un 400 DRY_RUN_UNSUPPORTED, gratuit. Le premier passage liste donc les élèves sans les prévenir, pour le seul prix des lectures.
Dans n8n
- Choisis Import from URL… et colle
https://fitdistance.io/documentation/api/cas-pratiques/eleve-inactif-relance.n8n.json, ou télécharge le workflow et choisis Import from File…. Choisis l'identifiantFit'Distance APIde Brancher n8n dans chaque nœud HTTP Request. - Exécute-le et lis la sortie de Students to remind : un élément par élève, avec son texte.
L'envoi écrit à de vrais élèves
Send message est livré désactivé : active-le seulement après ce premier passage. L'Idempotency-Key évite un doublon le même jour, pas d'un lundi à l'autre : un élève inactif est relancé chaque semaine, donc déclenche une semaine sur deux pour espacer.
- Active Send message, exécute à nouveau, puis active le workflow. Il envoie un message par seconde au plus.
Le texte est en haut du code de Students to remind. La boucle est celle de Brancher n8n, plus un nœud Code, Collect workouts, qui garde les identifiants des pages lues.
Dans Make
- Premier module HTTP › Make a request sur
GET /me; planning sur son horloge : chaque lundi. - HTTP › Make a request :
GETsurhttps://api.fitdistance.io/api/partner/v1/workouts,limit=200,status=done,since={{addDays(now; -14)}}. Un filtre sur le lien qui suit :has_moreégal àfalse, pour s'arrêter plutôt que de relancer à tort un élève dont la séance est sur la page suivante (n8n lit toutes les pages). Puis un Iterator surdata, un filtreifempty(ended_at; updated_at)postérieur ou égal à{{addDays(now; -14)}}et un Flow Control › Array aggregator surstudent_id. - HTTP › Make a request :
GETsur/studentsaveclimit=200, un Iterator surdata, puis un filtre :joined_atantérieur à{{addDays(now; -14)}},contract_statusdifférent dePAUSEDet deEXPIRED, etcontains(map(<tableau agrégé>; student_id); id)faux. - Lis le résultat du filtre, puis ajoute HTTP › Make a request :
POSTsur/operations/messaging.send,Idempotency-Key=inactif-{{id}}-{{formatDate(now; YYYY-MM-DD)}}, Body content typeapplication/JSON, Body input methodJSON string, corps{"text": "…", "studentId": {{id}}}.
Référence : élèves, entraînement, envoi d'un message.