KinesteX

Session Auth & Managed Subscriptions

Let users browse KinesteX views and chat with the AI trainer for free, while workout generation requires an active subscription that your backend controls. KinesteX stores each user's subscription status and enforces it server-side — the client app can't bypass it.


Fully optional. If you never set a subscription status, nothing changes for your users.


All management calls are server-to-server with your API key (x-api-key header). Never ship the API key in your app.


The flow:


1. Mint a session for the user, declaring their subscription status:


bash
1curl -X POST https://data.kinestex.com/api/sessions \
2  -H "x-api-key: YOUR_API_KEY" -H "content-type: application/json" \
3  -d '{"user_id": "user-123", "is_subscribed": false}'
4# → { "session_id": "ksx_sess_…", "user_id": "user-123", "is_subscribed": false, "expires_at": "…" }

2. Launch the KinesteX view with that session_id as usual — the SDK authenticates server-side and the raw API key never reaches the client. The user can browse, complete onboarding, and chat freely.


3. At the generation step, KinesteX posts { "type": "open_subscription_flow", "source": "generate_workout" } to your app instead of generating. Present your paywall on top of the KinesteX view.


4. After the purchase, grant the subscription from your backend, then tell the view the flow finished by posting { "subscription_result": "purchased" } (or "dismissed") into the webview. On "purchased" the parked generation resumes automatically — no extra tap.


Managing subscriptions:


ActionCall
GrantPOST /api/user-subscriptions {"user_id": "user-123"} — idempotent; creates the user if they've never launched
RevokeDELETE /api/user-subscriptions/user-123 — blocks generation from their next attempt
List activeGET /api/user-subscriptions?limit=100&offset=0
Set at session mintPOST /api/sessions with "is_subscribed": true/false — omit to leave the stored status unchanged

Status changes take effect on the user's next request — no relaunch needed.


Rules & enforcement:

  • Status is tri-state: never set → nothing is gated (default); true → generation allowed; false → generation blocked.
  • Only generation is gated (creating, modifying, or getting a recommended workout). Q&A, results discussion, and starting an already-generated workout stay available.
  • Enforcement is server-side: an unsubscribed generation attempt returns 403 {"code": "not_subscribed"} and the view re-opens your subscription flow. Reporting "purchased" without actually granting on the backend will not unlock generation.
  • For users with a backend-managed status, that status overrides the isSubscribed launch flag. Users without one keep the launch-flag behavior unchanged.

Web/redirect integrations (no host app): pass subscriptionReturnUrl in the launch config instead. KinesteX redirects there at the generation step; after purchase, send the user back with a fresh session — generation unlocks automatically.


For the client-side handshake (events, edge cases, per-platform code), see the subscription gating guide.


Blocking views for a user (`excluded_options`). Add excluded_options when you mint the session to stop that user from opening specific KinesteX views:


bash
1curl -X POST https://data.kinestex.com/api/sessions \
2  -H "x-api-key: YOUR_API_KEY" -H "content-type: application/json" \
3  -d '{"user_id": "user-123", "excluded_options": ["trainer", "challenge"]}'
4# → { "session_id": "ksx_sess_…", "user_id": "user-123", "excluded_options": ["trainer", "challenge"], "expires_at": "…" }

ValueBlocks
trainerAI Trainer chat
workoutWorkout view
custom-workoutCustom workout view
planPlan view, including plan onboarding
personalized-planPersonalized plan flow
challengeChallenge view
experienceGames and assessments
cameraCamera component
homeThe full KinesteX home experience

  • The list is saved on the user and applies to every later session until you send a new one. A new list replaces the old one, [] removes all exclusions, and leaving the field out keeps the saved list.
  • Values are case-insensitive. An unknown value fails the whole call with 400 and nothing is saved.
  • The check runs once, at launch, for the view you launch (the SDK sends its launch URL with the verify call). Screens the user reaches by navigating inside KinesteX are not checked, so excluding trainer does not hide the trainer inside the home experience; exclude home for that.
  • A blocked view doesn't load. It shows an error screen with "Cannot verify: " followed by the server's message (currently "You don't have access to this. Please contact app support.") and a back button. Your app receives error_occurred with severity: "critical" and the same text in data. The session stays valid for every other view.
  • If you call session-verify yourself for a blocked view, it returns 403 {"error": "…", "code": "access_excluded"}. Check code, not the message, and don't treat it as a sign-in failure.