Facebook Pixel
Fit'DistanceDocumentation
Open the app
On this page

Remind inactive students

Every Monday, send a short message to students with no finished workout for 14 days, with a first run that sends nothing.

Every Monday, students with no finished workout for 14 days get a message in the app. This use case writes in your name: it needs a key with Students › Read (students:read), Training › Read (training:read) and Messages › Write (messaging:write), and an offer that includes writes. Create the key in the app, terms of use accepted. A student's login cannot be read through the API: the use case looks at finished workouts. An event will replace this polling.

What this use case does

  1. Trigger: every Monday, then GET /me for coach.first_name, the signature (free).
  2. Workouts: GET /workouts?status=done&since=<14 days ago>, every page (status is scheduled, done, in_progress, draft or missed). since applies to updated_at: so keep only the student_id of the workouts whose ended_at, or updated_at if missing, is greater than or equal to 14 days ago.
  3. Students: GET /students, every page. Each student missing from that set gets a message, unless the student joined less than 14 days ago or has a PAUSED or EXPIRED contract.
  4. Send: one POST /operations/messaging.send per student reminded.
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": "Hi Léa, …", "studentId": 42}'

The Idempotency-Key is inactif-<id>-<YYYY-MM-DD>, with the date of the run: a replay the same day is refunded. See Writes and idempotency.

The message

Hi Léa, I haven't seen a finished workout from you in two weeks. If something is in your way, tell me here.

Mathias

What it costs

A page read costs one credit, debited before the call; each message sent costs one. A hundred students with three workouts a week: 600 workouts in 14 days, so 14 pages read with limit=50, 4 with limit=200, students included, then one message per student reminded. At this volume, the workouts take more than one page and the Make scenario stops on every run: use n8n or a script. A refused parameter still costs a credit; a 401, a 403 or a 429 costs nothing; a replay is refunded.

A first run that sends nothing

messaging.send has no preview by studentId: dry_run: true gives a 400 DRY_RUN_UNSUPPORTED, free. So the first run lists the students without messaging them, for the price of the reads only.

In n8n

  1. Choose Import from URL… and paste https://fitdistance.io/documentation/api/cas-pratiques/eleve-inactif-relance.n8n.json, or download the workflow and choose Import from File…. Pick the Fit'Distance API credential from Connect n8n in each HTTP Request node.
  2. Run it and read the output of Students to remind: one item per student, with its text.

Sending writes to real students

Send message ships disabled: enable it only after this first run. The Idempotency-Key prevents a duplicate the same day, not from one Monday to the next: an inactive student is reminded every week, so trigger every other week to space them out.

  1. Enable Send message, run again, then activate the workflow. It sends at most one message per second.

The text is at the top of the code of Students to remind, in French: replace it with the English message above. The loop is the one of Connect n8n, plus a Code node, Collect workouts, that keeps the ids of the pages read.

In Make

  1. First module HTTP › Make a request on GET /me; schedule on its clock: every Monday.
  2. HTTP › Make a request: GET on https://api.fitdistance.io/api/partner/v1/workouts, limit = 200, status = done, since = {{addDays(now; -14)}}. A filter on the link that follows: has_more equal to false, to stop rather than wrongly remind a student whose workout is on the next page (n8n reads every page). Then an Iterator on data, a filter ifempty(ended_at; updated_at) later than or equal to {{addDays(now; -14)}} and a Flow Control › Array aggregator on student_id.
  3. HTTP › Make a request: GET on /students with limit = 200, an Iterator on data, then a filter: joined_at earlier than {{addDays(now; -14)}}, contract_status different from PAUSED and EXPIRED, and contains(map(<aggregated array>; student_id); id) false.
  4. Read the result of the filter, then add HTTP › Make a request: POST on /operations/messaging.send, Idempotency-Key = inactif-{{id}}-{{formatDate(now; YYYY-MM-DD)}}, Body content type application/JSON, Body input method JSON string, body {"text": "…", "studentId": {{id}}}.

Reference: students, training, sending a message.

Next pageAn online purchase → an invitationWhen a customer pays on Stripe, invite them to your coaching with Fit'Distance, after a first run as a preview, with n8n or Make.