Get All Clubs

URL: https://api.gradual-api.com/public-api/v1/clubs

HTTP Method: GET

Content type: application/json

Tier: Medium

Response Example:

[
{
"clubId": "6553ce608b3f645e79d95034",
"name": "Engineering",
"slug": "engineering",
"accessType": "Open"
},
{
"clubId": "6553ce608b3f645e79d95035",
"name": "Product Leaders",
"slug": "product-leaders",
"accessType": "Private"
}
]

Get Club Application Requests

URL: https://api.gradual-api.com/public-api/v1/clubs/:clubId/application-requests

HTTP Method: GET

Content type: application/json

Tier: Medium

Returns a paginated list of membership application requests for a club. Supports filtering by status, applicant attributes, and member type, plus sorting. Each request includes the applicant's profile, the form answers they submitted (if any), and the operator who approved/declined it (if any).

Path Parameters:

  • clubId, string, required, the club's ID

Query Parameters:

All parameters are optional.

  • status, string, filter by request status, one of Pending, Accepted, Declined, Expired. When omitted, requests of all statuses are returned.
  • pageNum, integer (≥ 1), the page number to retrieve (1-based), defaults to 1
  • pageSize, integer (1–200), number of requests per page, defaults to 50
  • sort, string, sort order, one of DEFAULT, CREATED_AT_ASC, CREATED_AT_DESC, NAME_ASC, NAME_DESC, defaults to DEFAULT
    • DEFAULT and CREATED_AT_DESC — newest requests first
    • CREATED_AT_ASC — oldest requests first
    • NAME_ASC / NAME_DESC — by applicant display name (A→Z / Z→A), newest first as a tie-breaker
  • memberName, string, free-text filter on the applicant's display name
  • email, string, free-text filter on the applicant's email
  • title, string, free-text filter on the applicant's job title/position
  • company, string, free-text filter on the applicant's company name
  • memberType, string, filter by member type, one of Standard, Guest, Limited Approval

Response Example:

{
"totalCount": 150,
"size": 50,
"pageNumber": 1,
"pageSize": 50,
"results": [
{
"id": "60d5ec49c1234567890abcd1",
"status": "Pending",
"operatedAt": null,
"createdAt": "2026-06-24T10:30:00.000Z",
"expiredAt": null,
"operator": null,
"form": {
"id": "60d5ec49c1234567890abcf0",
"questionnaire": {
"Why do you want to join?": ["Professional networking", "Learning"],
"Years of experience": ["5+"]
}
},
"applicant": {
"userId": "60d5ec49c1234567890abcde",
"userEmail": "[email protected]",
"userFirstName": "Jane",
"userLastName": "Doe",
"displayName": "Jane Doe",
"userTitle": "Senior Engineer",
"userCompany": "Acme Inc.",
"userLinkedIn": "https://www.linkedin.com/in/janedoe",
"userLocation": "San Francisco, CA, United States",
"userAvatarUrl": "https://cdn.example.com/avatars/jane.png",
"memberType": "Standard",
"approvalStatus": "Approved",
"spaces": ["General"],
"questionnaire": {
"What are your interests?": "Design;Engineering"
},
"signUpAt": "2026-01-15T08:00:00.000Z",
"lastLoginAt": "2026-06-24T15:30:00.000Z",
"onboardingAt": "2026-01-16T10:00:00.000Z",
"lifetimePoints": 150,
"remainingPoints": 50
}
},
{
"id": "60d5ec49c1234567890abcd2",
"status": "Accepted",
"operatedAt": "2026-06-20T09:15:00.000Z",
"createdAt": "2026-06-18T11:00:00.000Z",
"expiredAt": null,
"operator": {
"id": "60d5ec49c1234567890abc99",
"displayName": "Club Admin"
},
"form": null,
"applicant": {
"userId": "60d5ec49c1234567890abcf1",
"userEmail": "[email protected]",
"userFirstName": "John",
"userLastName": "Smith",
"displayName": "John Smith",
"userTitle": "Product Manager",
"userCompany": "Globex",
"userLinkedIn": "",
"userLocation": "London, UK",
"userAvatarUrl": "",
"memberType": "Standard",
"approvalStatus": "Approved",
"spaces": [],
"questionnaire": {},
"signUpAt": "2026-02-01T08:00:00.000Z",
"lastLoginAt": "2026-06-19T12:00:00.000Z",
"onboardingAt": "2026-02-01T09:00:00.000Z"
}
}
]
}

Response Fields:

  • totalCount, number, total number of requests matching the filter across all pages
  • size, number, the number of requests returned in this page (i.e. results.length)
  • pageNumber, number, the page that was returned (echoes pageNum)
  • pageSize, number, the page size that was applied
  • results, array, the list of application request objects

Each application request object contains:

  • id, string, the application request's unique identifier
  • status, string, the request status: Pending, Accepted, Declined, or Expired
  • operatedAt, string, ISO 8601 timestamp of when the request was approved/declined; null if not yet operated on
  • createdAt, string, ISO 8601 timestamp of when the request was created
  • expiredAt, string, ISO 8601 timestamp of when the request expires; null if not applicable
  • operator, object, the member who approved/declined the request; null if the request has not been operated on
    • operator.id, string, the operator's user ID (a historical operator who has since been archived is still returned)
    • operator.displayName, string, the operator's display name; null if unavailable
  • form, object, the application form the applicant submitted; null if no form was submitted
    • form.id, string, the form's unique identifier
    • form.questionnaire, object, map of question title → array of answer values; contains only answered questions (empty object {} if nothing was answered)
  • applicant, object, the applicant's profile, with the same fields as the Get a User by User ID response; null if the applicant is no longer an active member. The applicant's memberType is the human-readable label (Standard, Guest, or Limited Approval) — the same values accepted by the memberType query parameter above.

Notes:

  • Returns 400 if the clubId is malformed, the club does not exist, or it belongs to a different tenant.
  • Returns 400 if a parameter value is invalid (e.g. pageSize > 200, or an unrecognized status, sort, or memberType).
  • Some applicant fields may be masked or omitted depending on your tenant's profile field visibility settings.

Get a User's Clubs by User ID

URL: https://api.gradual-api.com/public-api/v1/users/:userId/clubs

HTTP Method: GET

Content type: application/json

Tier: Light

Path Parameters:

  • userId, string, required, this is the unique identifier to find a user

Response Example:

{
"userEmail": "[email protected]",
"userFirstName": "test_first",
"userLastName": "test_last",
"userId": "6553ce608b3f645e79d95034",
"userClubs": [
{
"clubId": "6553ce608b3f645e79d95034",
"name": "Club 1",
"slug": "club-1"
}
]
}

Add a User to a Club

URL: https://api.gradual-api.com/public-api/v1/clubs/:clubId/users

HTTP Method: POST

Content type: application/json

Tier: Medium

Path Parameters:

  • clubId, string, required, this is the unique identifier to find a club

Request Body Parameters:

  • userId, string, optional, this is the unique identifier to find a user (at least one of userId or email is required)
  • email, string, optional, this is the unique identifier to find a user (at least one of userId or email is required)

Response Example:

{
"success": true
}

Delete a User from a Club

URL: https://api.gradual-api.com/public-api/v1/clubs/:clubId/users

HTTP Method: DELETE

Content type: application/json

Tier: Medium

Path Parameters:

  • clubId, string, required, this is the unique identifier to find a club

Request Body Parameters:

  • userId, string, optional, this is the unique identifier to find a user (at least one of userId or email is required)
  • email, string, optional, this is the unique identifier to find a user (at least one of userId or email is required)

Response Example:

{
"success": true
}

Update User Clubs

URL: https://api.gradual-api.com/public-api/v1/updateUserClubs

HTTP Method: POST

Content type: application/json

Tier: Medium

Updates a user's club memberships. Supports two modes: add to add clubs to the user's existing memberships, or override to replace all current memberships with the specified clubs.

Request Body Parameters:

  • email, string, optional, the user's email address
  • userId, string, optional, the user's ID
  • clubIds, array of strings, optional, list of club IDs (up to 10)
  • clubNames, array of strings, optional, list of club names (up to 10)
  • mode, string, required, either add or override
    • In add mode, the user's existing memberships are preserved and the specified clubs are added
    • In override mode, the user will be removed from any clubs not in the provided list
    • Use mode = "override" with clubIds/clubNames = [] to remove user from all clubs

Either email or userId must be provided. Either clubIds or clubNames must be provided.

Request Body Example 1:

{
"email": "[email protected]",
"clubNames": ["Engineering", "Product"],
"mode": "add"
}

Request Body Example 2:

{
"userId": "6553ce608b3f645e79d95034",
"clubIds": ["6553ce608b3f645e79d95040", "6553ce608b3f645e79d95041"],
"mode": "override"
}

Response Example:

{
"userEmail": "[email protected]",
"userId": "6553ce608b3f645e79d95034",
"userFirstName": "Jane",
"userLastName": "Doe",
"oldClubs": [
{
"clubId": "6553ce608b3f645e79d95040",
"name": "Engineering",
"slug": "engineering"
}
],
"newClubs": [
{
"clubId": "6553ce608b3f645e79d95040",
"name": "Engineering",
"slug": "engineering"
},
{
"clubId": "6553ce608b3f645e79d95041",
"name": "Product",
"slug": "product"
}
],
"results": [
{
"clubName": "Engineering",
"clubId": "6553ce608b3f645e79d95040",
"status": "already_member"
},
{
"clubName": "Product",
"clubId": "6553ce608b3f645e79d95041",
"status": "success"
}
]
}

Per-Club Result Statuses:

  • success — user was successfully added to the club
  • already_member — user is already a member of the club (no action taken)
  • failed — operation failed, see reason field for details

Notes:

  • Duplicate values within clubIds or clubNames are rejected with a 400 error.
  • If mode is add and no valid clubs are resolved, the request is rejected with a 400 error.
  • Returns 400 if the user is not found or has been archived.

Batch Add Club Members

URL: https://api.gradual-api.com/public-api/v1/clubs/:clubId/users/batch

HTTP Method: POST

Content type: application/json

Tier: Heavy

This endpoint adds multiple users to a club in a single request. The operation is processed asynchronously — you receive a job ID immediately and poll for results.

Path Parameters:

  • clubId, string, required, the club's ID

Request Body Parameters:

  • users, array, required, array of user objects (1–100 items)
  • users[].email, string, optional, must be a valid email address
  • users[].userId, string, optional, the user's ID

Each user object must have at least one of email or userId.

Request Body Example:

{
"users": [
{
"email": "[email protected]"
},
{
"userId": "6553ce608b3f645e79d95034"
},
{
"email": "[email protected]",
"userId": "6553ce608b3f645e79d95035"
}
]
}

Response Example (202 Accepted):

{
"jobId": "6553ce608b3f645e79d95034",
"status": "pending"
}

Notes:

  • The club must exist, otherwise a 400 error is returned. Individual users are validated during async job processing.
  • The maximum batch size is 100 users per request.
  • Poll the Get Batch Club Member Job Status endpoint to check the results after submitting.

Get Batch Club Member Job Status

URL: https://api.gradual-api.com/public-api/v1/clubs/:clubId/users/batch/:jobId

HTTP Method: GET

Content type: application/json

Tier: Light

Path Parameters:

  • clubId, string, required, the club's ID
  • jobId, string, required, the job ID returned from the batch add request

Response Example (job completed):

{
"jobId": "6553ce608b3f645e79d95034",
"status": "completed",
"results": [
{
"recordPosition": 0,
"email": "[email protected]",
"status": "success"
},
{
"recordPosition": 1,
"userId": "6553ce608b3f645e79d95034",
"status": "success"
}
]
}

Response Example (job with partial failures):

{
"jobId": "6553ce608b3f645e79d95034",
"status": "completed",
"results": [
{
"recordPosition": 0,
"email": "[email protected]",
"status": "success"
},
{
"recordPosition": 1,
"email": "[email protected]",
"status": "failed",
"reason": "user not found"
}
]
}

Job Statuses:

  • pending — job is queued and waiting to be processed
  • processing — job is currently being processed
  • completed — all members have been processed (check individual results for per-member status)
  • failed — job encountered a fatal error

Per-Member Result Statuses:

  • success — user was successfully added to the club
  • failed — operation failed, see reason field for details

Notes:

  • A completed job does not mean all members were added successfully. Always check the individual results entries for per-member status.
  • The recordPosition field corresponds to the index of the user in the original users array (starting from 0).
  • Returns 404 if the job is not found or does not belong to the specified club.