GOFA Client API Documentation
This document describes the available endpoints under /api/client for client integrations.
Authentication
POST /api/client/token/
Obtain a JWT token for client API access.
Request Body:
{
"clientId": "string",
"clientSecret": "string"
}
Response:
200 OK:{ token: "string" }400 Bad Request:{ error: "string" }401 Unauthorized:{ error: "string" }500 Internal Server Error:{ error: "string" }
Authentication Methods
The API supports multiple authentication methods. Use any one of the following:
ClientToken (Recommended)
JWT-based authentication for client applications. Obtained from /api/client/token/.
ClientToken: <jwt_token>
Firebase ID Token
Firebase Authentication ID token for user-specific operations.
Authorization: Bearer <firebase_id_token>
Legacy Methods (Deprecated)
AdminToken: <admin_token>- Legacy admin authenticationRevokableToken: <revokable_token>- Legacy revokable token authentication
Note: Session cookies are also supported as a fallback authentication method.
Users
GET /api/client/[clientId]/users
List all users for a client, or search for a user by exact email match using the email query parameter.
Headers:
ClientToken: <client_token>ORAuthorization: Bearer <firebase_id_token>ORAdminToken: <admin_token>(deprecated)
Query Parameters:
email(optional): If provided, returns the user with the exact matching email. If not found, returnsuser: null.userType(optional): Filter by user type - 'player', 'cms', or 'silverCare'.search(optional): Search across displayName, email, and phoneNumber fields.attributeKey(optional): Search by custom attribute key (requiresattributeValue).attributeValue(optional): Exact value to match for the specifiedattributeKey.sortBy(optional): Sort field - 'createdAt', 'updatedAt', 'displayName', or 'email'. Default: 'createdAt'.sortDesc(optional): Sort in descending order. Default: false.limit(optional): Maximum number of results. Default: 50.offset(optional): Number of results to skip for pagination. Default: 0.
Note: When using attributeKey and attributeValue, the search will find users with exact matches in their attributes field. For example, ?attributeKey=className&attributeValue=yoga-101 will find users where attributes.className equals "yoga-101".
Response:
200 OK:{ users: Array<User> }(if noemailparameter){ user: User }(ifemailparameter and user found){ user: null }(ifemailparameter and no user found)
401 Unauthorized:{ error: string }400 Bad Request:{ error: string }500 Internal Server Error:{ error: string }
POST /api/client/[clientId]/users
Create a new user for a client. This endpoint creates a Firebase Auth user and a corresponding Firestore user document.
Headers:
ClientToken: <client_token>ORAuthorization: Bearer <firebase_id_token>ORAdminToken: <admin_token>(deprecated)
Request Body:
All fields except those marked optional are required.
{
"email": "string (valid email)",
"password": "string (min 6 chars)",
"firstName": "string (min 2 chars)",
"lastName": "string",
"gender": "MALE" | "FEMALE" | "OTHER" | "UNSPECIFIED" (optional),
"birthDate": "YYYY-MM-DD" (optional),
"height": integer (optional),
"weight": integer (optional),
"activityLevel": "LOW" | "MEDIUM" | "HIGH" (optional),
"fitnessLevel": "BEGINNER" | "INTERMEDIATE" | "ADVANCED" (optional),
"attributes": {
"customKey1": "any value",
"customKey2": 123,
"customKey3": true
} (optional)
}
Response:
-
200 OK:{
"success": true,
"customToken": "string",
"uid": "string",
"user": {
/* user object */
}
} -
400 Bad Request:{ errors: { field: [messages] } }(validation error) -
401 Unauthorized:{ error: string } -
409 Conflict:{ error: string }(user already exists) -
500 Internal Server Error:{ error: string }
Notes:
- Do not include
userIdornamein the request body. The user ID is generated by Firebase Auth. - Only fields listed above are accepted; unknown fields will be rejected.
- The returned
customTokencan be used to sign in the user immediately after registration.
GET /api/client/[clientId]/users/[userId]
Get a specific user by ID.
Headers:
ClientToken: <client_token>ORAuthorization: Bearer <firebase_id_token>ORAdminToken: <admin_token>(deprecated) ORRevokableToken: <revokable_token>(deprecated)
Response:
200 OK:{ user: User }404 Not Found:{ error: string }401 Unauthorized:{ error: string }400 Bad Request:{ error: string }500 Internal Server Error:{ error: string }
PATCH /api/client/[clientId]/users/[userId]
Update fields for a user.
Headers:
ClientToken: <client_token>ORAuthorization: Bearer <firebase_id_token>ORAdminToken: <admin_token>(deprecated) ORRevokableToken: <revokable_token>(deprecated)
Request Body:
{
// ...fields to update (only fields defined in the schema are accepted)
}
Field Validation:
- Only the following fields defined in the user schema are accepted. Attempts to patch unknown fields will result in a
400 Bad Requesterror with details.
Allowed fields:
email(string, optional)displayName(string, optional)photoURL(string, optional)cms(object, optional)status(string, required)role(enum, optional)
player(object, required)status(string, required)
personalInfo(object, optional)firstName(string, optional)lastName(string, optional)gender(enum, optional) — one of"MALE","FEMALE","NON_BINARY","UNDEFINED"birthDate(string, optional, ISO date)height(number, optional)weight(number, optional)activityLevel(enum, optional) — one of"NOT_ACTIVE","LOW","MODERATE","HIGH"fitnessLevel(enum, optional) — one of"BEGINNER","INTERMEDIATE","ADVANCED"
locale(enum, optional)settings(object, optional)lessons(object, optional)bookmarkedLessonIds(array of strings, optional)skipWarmUp(boolean, optional)skipCoolDown(boolean, optional)
challenge(object, optional)bookmarkedChallengeIds(array of strings, optional)
attributes(object, optional) — Custom key-value pairs for third-party integrations- Any keys and values (strings, numbers, booleans, arrays, objects) are allowed
Response:
200 OK:{ success: true }400 Bad Request:{ error: string, details?: any }(invalid or unknown fields)401 Unauthorized:{ error: string }500 Internal Server Error:{ error: string }
DELETE /api/client/[clientId]/users/[userId]
Delete a user and optionally their associated data.
Headers:
ClientToken: <client_token>ORAuthorization: Bearer <firebase_id_token>ORAdminToken: <admin_token>(deprecated) ORRevokableToken: <revokable_token>(deprecated)
Request Body (Optional):
{
"deleteUserData": boolean (optional, default: true)
}
Request Body Fields:
-
deleteUserData(optional, default:true): Whentrue, deletes all associated user data including:- Fall risk assessment results
- Lesson play records
When
false, only deletes the user document itself.
Response:
-
200 OK:{
"success": true,
"deletedUserData": boolean
} -
401 Unauthorized:{ error: string } -
400 Bad Request:{ error: string } -
500 Internal Server Error:{ error: string }
Notes:
- The deletion is performed atomically using Firestore batch operations.
- If no request body is provided,
deleteUserDatadefaults totrue. - Invalid JSON in the request body is ignored and defaults are used.
Working with Custom Attributes
The attributes field allows third-party partners to store custom data alongside user records. This field accepts any key-value pairs and is completely flexible.
Creating Users with Attributes
POST /api/client/[clientId]/users
{
"email": "user@example.com",
"password": "password123",
"firstName": "John",
"lastName": "Doe",
"attributes": {
"className": "yoga-101",
"centerName": "Downtown Wellness",
"caregiverName": "Jane Smith",
"membershipLevel": "premium",
"joinDate": "2024-01-15",
"preferences": {
"notifications": true,
"language": "en"
}
}
}
Updating Attributes
You can update the entire attributes object or merge new values:
PATCH /api/client/[clientId]/users/[userId]
{
"attributes": {
"className": "advanced-yoga",
"lastVisit": "2024-09-02",
"completedSessions": 15
}
}
Searching by Attributes
Find users by specific attribute values:
GET /api/client/[clientId]/users?attributeKey=className&attributeValue=yoga-101
GET /api/client/[clientId]/users?attributeKey=centerName&attributeValue=Downtown%20Wellness
Important Notes:
- Attribute searches perform exact matches only
- For complex queries involving multiple attributes, consider fetching users and filtering client-side
- Firestore automatically creates indexes for single-field queries, but composite indexes may be needed for complex multi-field searches
JWT ClientId Validation
All endpoints that require authentication now validate that the clientId in the JWT matches the clientId in the request path. If they do not match, the API will return:
401 Unauthorized:{ error: "Token clientId does not match request clientId" }
This applies to:
GET /api/client/[clientId]/usersPOST /api/client/[clientId]/usersGET /api/client/[clientId]/users/[userId]PATCH /api/client/[clientId]/users/[userId]DELETE /api/client/[clientId]/users/[userId]
Ensure your JWT is generated for the correct client.
Notes
- All endpoints require a valid JWT obtained from
/api/client/token/except for the token endpoint itself. - All responses are JSON.
- User object fields depend on your integration and may include custom fields.