Check-in
The code is dead before it reaches the car park.
A member opens the app and it draws a fresh QR. Sixty seconds later that code is refused, everywhere, including at the desk it was made for. Screenshot it and send it to a friend and the friend gets turned away — not by a staff member making a judgement call, by the server declining an expired signature.
01 / The code
Four values and a deadline
It is not a picture of a member number. It is a signed token, and the four things inside it are the four things the desk needs to decide.
The app asks the server for a code. The server builds a JSON Web Token, signs it with its own key, and stamps it to expire sixty seconds from that moment. The app renders that string as a QR.
Nothing about the code is guessable and nothing about it is durable. A member cannot make one for somebody else, because the signature is the server's. A member cannot bank one for later, because the clock is inside the token rather than inside the app.
The two gym ids matter more than they look. home_fc_id is where the membership lives. scan_fc_id is the gym the code was asked for. When those differ, the desk is looking at a visiting member and the software knows to check All-Access rules instead of ordinary ones.
What is inside the token
- customer_id
- The member record
- cust_user_id
- The login behind it
- home_fc_id
- Where the membership lives
- scan_fc_id
- Where the code was asked for
- exp
- Issued time plus 60 seconds
- Signature
- HS256, server key
02 / The scan
What happens in the two seconds at the desk
Five checks, in this order. Any one of them failing is a refusal with a reason on the screen, not a silent nothing.
-
The app asks for a code
One call, one token, sixty seconds on the clock. The same response tells the app how many All-Access sessions the member has left, so the member sees that on the same screen as the code rather than finding out at a strange gym's counter.
-
The desk scans it
Staff hit one endpoint with the scanned string. There is no shared secret in the scanner and nothing to configure per till.
-
The signature and the clock are checked first
A token that has been edited fails the signature. A token older than sixty seconds fails the clock. Both are refused before the member is looked up at all.
-
The member's own row is locked
Two staff double-tapping the same code, or a phone retrying on a bad connection, would otherwise write two attendance rows. The check-in takes a database lock on that member's profile, so the second attempt reads the first one and stops. One check-in per member per gym per day, and the second gets told the member is already in.
-
If it is not their gym, All-Access rules apply
The scanning gym has to be switched on for visiting members, the member's plan has to have sessions left, and one session is consumed per day per gym — not per scan. An audit row records which gym used which session, so the settlement between branches is a report rather than an argument.
03 / How much of this has actually happened
Counted off the production database, 23 August 2026
These are queries, not estimates, and they cover every check-in path together — QR, gym code, fingerprint, face and card. Ask us to run them again in front of you.
12,370,692
member check-ins recorded since December 2023
1,529,290
of them in the last thirty days
191
fitness centres that checked somebody in during the last ninety days
305
fitness centres on the platform in total, busy and quiet alike
We are showing you both centre numbers on purpose. 305 is everyone with an account. 191 is everyone who put a real person through a door in the last quarter. The second number is the one that means anything, and most software companies only print the first.
04 / When the camera will not play
Three ways in, and what each one costs you
Bad light, a cracked lens, a member who left their phone in the car. The QR is the good path, not the only one.
| Path | What the member does | The honest limit |
|---|---|---|
| Dynamic QR | Opens the app, holds up the code, staff scan it | Sixty seconds of life. Needs a working camera at the desk. |
| Gym code | Types the gym's short code into their own app | No scanner involved, so nobody at the desk sees it happen. The same All-Access rules, session deduction and once-a-day rule still apply. |
| Open the gate from the app | Presses a button; the command is queued onto the gym's terminals | At their own gym, no location check. At a partner gym, their phone's GPS has to be within 150 metres of the pinned address or it is refused. |
All three write to the same attendance table, so the footfall report does not care which one a member used.
05 / The part nobody advertises
Your internet goes down. Does an expired member get in?
On most systems, yes. Blocking an expired member is a command sent to the door terminal, and if the terminal cannot reach the server there is no command. Two terminals in our own fleet sat offline for two and three weeks with hundreds of queued commands behind them. For those weeks, expired members walked in.
The fix is to stop sending the block and send the calendar instead. When a membership is sold or renewed, the member's start and end dates are written into the terminal itself, in advance. On the expiry date the terminal refuses the finger on its own, with nothing plugged in and nobody watching. A renewal re-opens the window the same way.
Verified live on 18 August 2026 against a ZAM180-NF50VA running push firmware 2.0.33S: the window was accepted, and a re-read of the device's own roster confirmed it had stuck.
The validity window
- Sent
- When a plan is sold, renewed or expires
- Carries
- Start date, end date, enforce flag
- Enforced by
- The terminal, offline
- Cleared by
- A renewal, which reopens the window
Bring the awkward question
The demo is a screen share on live software, not a slide deck. Ask us to generate a code and let it die on camera. Ask what happens when the internet drops. We will answer with the screen, or we will tell you it is not built.
Or email crm.sales@proultimate.com directly.