Company opt-in and scopes
A company administrator or authorized staff member creates a Public API OAuth client throughPOST /app/v1/integrations/public-api/clients, using their coach
token and the integrations.api_credentials.create permission. The company must
have Public API provider access. The company is derived from that authenticated
context; do not pass a company ID.
This example enables client creation and app/AI grant synchronization:
externalAppAccessEnabled defaults to false. Set it at OAuth client creation;
client_app_access:write must be among that client’s configured scopes when the
option is true. Public API callers cannot enable it themselves. Add only the
workout scopes and explicit health consent required by your programme operations;
see authentication and consent.
Store the returned clientId and one-time clientSecret for the OAuth token
exchange. To rotate the secret later, use the returned _id with
POST /app/v1/integrations/public-api/clients/{id}/rotate-secret through the
company management API. Secret rotation preserves reference and grant ownership;
creating a replacement OAuth client creates a separate namespace.
For a new company-client relationship, the required external app-access policy
commits atomically with the relationship before any creation or linking email
runs. The same rule applies when linking an existing global account to a new
company relationship. Existing manual relationships are never silently taken
over. Existing creation/linking emails may arrive before an active grant has
been synchronized. An invitation alone does not provide app access; respect the
existing email behavior and do not send a duplicate invitation. Announce paid
activation only after the effective-access read confirms the requested rights.
client_access:read: read owned grants and current effective access.client_app_access:write: manage theappcapability.client_ai_access:write: manage theclient_aicapability.- Client and workout operations retain their existing scopes and consent gates.
Grant status versus client status
An external grant authorizes capabilities for one company-client relationship. Itsstatus is separate from the client’s relationship, membership and portal
statuses. Writing a grant does not activate, pause, archive or otherwise change
those lifecycle fields. See Client statuses and app access
for their values and supported mutations.
There is no stored
expired or scheduled grant status. An active grant can
be in the future or already expired. FITsociety checks its dates when evaluating
access; it does not rewrite the grant status when time passes.
For example, relationship.status: "active", portal status enabled and grant
status active can still produce effective.app: false after validUntil in
an externally managed relationship. A company block or portal restriction can
also prevent access during a grant’s valid interval. Always confirm the current
effective result instead of deriving it from one status field.
A deleted or missing global client account always has effective.app: false
and effective.clientAi: false. A new active revision then returns
403 access.client_unavailable. Owned grants remain readable and revocable for
reconciliation; an exact stored-grant revision replay does not reactivate the account.
Create, renew or revoke a grant
UsePUT /public/v1/clients/{clientId}/access-entitlements/{externalId}.
The identifier is opaque, at most 200 characters, and belongs to the authenticated
API client within its company. No payment provider prefix or billing cadence is
required. Every write also requires an Idempotency-Key.
Z, with validFrom < validUntil.
Access applies at validFrom <= now < validUntil. Expired intervals may be
recorded for reconciliation; they do not grant current access. Renew by updating
the same identifier with a newer positive safe-integer revision and a new paid
interval. Revoke with status: "revoked" and a newer revision. Retained records
prevent an older active message from restoring access. A relationship supports
at most 100 retained entitlement records; renew the same source entitlement
rather than creating a new record for each payment period.
Permissions are checked for every existing and requested capability, including
removal and revocation. A caller with only app-write scope cannot remove an AI
capability from an existing combined grant. A new active app+AI write is rejected
entirely with 403 access.ai_unavailable when AI is unavailable; the previous
grant is unchanged. Revocation remains possible without an AI licence.
Same revision and normalized content confirms the existing grant. An older
revision returns 409 access.stale_revision; conflicting content at the same
revision returns 409 access.revision_conflict. Secret rotation keeps the same
ownership identity. A new OAuth client is a separate source and requires an
explicit ownership migration; do not replace one to rotate its secret.
Confirm effective access
ReadGET /public/v1/clients/{clientId}/access-entitlements after synchronization.
The response includes only this API client’s grants and an effective summary:
{ data, meta } envelope. A successful stored-grant write does
not guarantee that the full product is currently accessible: company blocks,
portal policy, feature settings and licence changes still apply. HTTP idempotency
replays contain the original response snapshot; GET returns current state.
For externally managed relationships, an administrator company block also denies
login, company selection and existing-session access without modifying the grant.
Expiry is evaluated on existing authenticated sessions and access checks. It
needs neither a webhook nor a scheduled database update. Other valid grants and
manual AI rights remain independent. Revoking one integration’s grant cannot
remove another source’s access. There is no guaranteed grant-expiry webhook in
this version; integrations should read current state when needed.
Recoverable client and programme synchronization
Use durable external references for client, exercise and workout-plan identity. A typical server-side flow is:- Resolve the client by owned external ID; optionally find an existing client by exact email and bind its reference.
- Create or link a new client through the existing client API when needed.
- Resolve controlled exercise IDs and create the assigned programme through the existing workout API.
- Synchronize the paid access interval and read back effective app and AI access.
- Announce activation only when all requested capabilities are effective.