# Working with dynamic QR code access ## Intro Use case description of how to use the customer access code endpoint to generate dynamic, rotating QR codes for secure gym entry via the Open API. The access code model: - A single GET endpoint returns a short-lived access code per customer. - The response contains a `content` string to be rendered as a QR code, a `format` descriptor, and an `expiresAt` timestamp. - Codes are dynamic: each call returns a fresh code, and the previous code expires at the time indicated in `expiresAt`. - Depending on the studio's access control configuration, a code may also be invalidated immediately after a successful check-in. ## Relevant Endpoints - [GET customer's access code](../openapi/openapi/customers/getCustomerAccessCode) ## Dynamic QR code access The access code endpoint enables partners to build secure, dynamic QR code check-in screens in member-facing apps. The code is not static — it rotates on a schedule and is tied to a single customer, making it unsuitable for sharing or copying. Core behavior: - Each response returns a `content` string that must be rendered as a QR code using a client-side library. The `format` field will be `QR_CODE`. - `expiresAt` is an ISO 8601 date-time string indicating when the current code becomes invalid. This is used to drive countdown timers and auto-refresh logic. - Required scope: `CUSTOMER_READ`. - The endpoint takes a single path parameter: `customerId` (int64). Recommended use cases: - QR code check-in screen in a member app or web portal - Kiosk check-in where the app fetches a code for an attended session - Any integration requiring time-limited, per-member access credentials ## Display and refresh flow ### 1. Fetch the access code When the user opens the check-in screen, call `GET /v1/customers/{customerId}/access-code`. Use this to: - obtain the `content` string to render as a QR code - read `expiresAt` to start a countdown timer in the UI - determine the `format` — currently always `QR_CODE` ### 2. Render the QR code Pass the `content` value to a QR code generation library to produce a scannable image. Use this to: - display the QR code as the primary check-in element - pair it with a visible countdown so the member knows when to expect a refresh Best practice: - do not display the raw `content` string to users; render only the visual QR code - refresh the display immediately once a new code is fetched, not before the request completes ### 3. Handle expiry and auto-refresh Monitor the `expiresAt` timestamp client-side and trigger a new GET request before the code expires. Use this to: - ensure the member always has a valid code when they reach the turnstile - avoid situations where the user is left with an expired code during peak entry times Best practice: - refresh proactively — fetch a new code a few seconds before `expiresAt`, not after, to account for network latency - if `expiresAt` is absent from the response, apply a conservative fallback refresh interval ### 4. Handle post-check-in invalidation Some studio configurations invalidate the code immediately after a successful scan, regardless of `expiresAt`. Use this to: - detect that a code has been used and prompt the user to fetch a new one if they need to re-enter - avoid showing a stale code that will be rejected at the gate on subsequent attempts ## Complete workflow examples Note: The payload examples below are integration-oriented drafts. Validate all field names and structures against the current OpenAPI schema before publishing or implementation. ### Example: Display QR code on check-in screen Scenario: Member opens the app's check-in screen. The app fetches a fresh access code and displays the QR code with a countdown. 1. User navigates to check-in screen 2. App calls `GET /v1/customers/{customerId}/access-code` 3. App renders `content` as QR code and starts countdown using `expiresAt` 4. When countdown reaches ~5 seconds remaining, app calls the endpoint again 5. New `content` replaces the displayed QR code seamlessly Example GET response shape (illustrative): ```json { "format": "QR_CODE", "expiresAt": "2024-06-13T10:33:00Z", "content": "0049267681211943991" } ``` ## Common integration challenges - Rendering `content` as plain text: The `content` value is an opaque string that must be passed to a QR code library. Displaying it as text makes it unreadable at the gate. - No expiry handling: Ignoring `expiresAt` and showing a static code will result in entry failures once the code expires. Always implement timer-driven refresh. - Refresh after expiry instead of before: Fetching a new code only after `expiresAt` has passed means the user faces a brief gap with no valid code. Trigger the refresh a few seconds early. - Missing fallback for absent `expiresAt`: The field is optional in the schema. If it is not present, implement a conservative refresh interval rather than assuming the code is indefinitely valid. - Fetching on each render: Calling the endpoint every time the screen is drawn (e.g., on every component mount or page navigation) creates unnecessary load. Fetch once on entry and manage refresh via the timer pattern. ## Access code webhook events Check-in events are triggered when a customer successfully scans their QR code at the gate. Subscribe to these to track entry activity and build real-time dashboards or push notifications. Event reference: - [Event types](../webhooks/event-types/)