Skip to main content

Groups

Base URL: https://api-sls.platzi.com/production-sls-business-domains

Key Features:

  • CRUD operations for company teams/groups
  • User-to-group assignment and management
  • Group-based learning path management
  • State management (active, archived, deleted)
  • Bulk user operations with partial success handling
  • Pagination and search capabilities

API Endpoints​

GET /v3/group-builder/{company_id}/groups/​

List all groups for a company with optional filters.

Path Parameters:

  • company_id (int) - Company ID

Query Parameters:

ParameterTypeRequiredDescription
statestringNoFilter by state: active, archived, deleted (default: active)
group_idsstringNoComma-separated group IDs to filter
searchstringNoSearch by group name
pageintNoPage number (default: 1)
page_sizeintNoItems per page (default: 20)

Example Request:

GET /v3/group-builder/123/groups/?state=active&search=engineering&page=1&page_size=20

Response:

{
"data": [
{
"id": 456,
"group_id": 456,
"name": "Engineering Team",
"description": "Software engineers and developers",
"color": "#3498db",
"state": 0,
"students_count": 25,
"created_at": "2025-01-20T10:00:00",
"updated_at": "2025-01-20T10:00:00"
},
{
"id": 457,
"group_id": 457,
"name": "Engineering - Backend",
"description": "Backend developers",
"color": "#2ecc71",
"state": 0,
"students_count": 12,
"created_at": "2025-01-21T09:00:00",
"updated_at": "2025-01-21T09:00:00"
}
],
"metadata": {
"count": 45,
"pages": 3,
"current_page": 1,
"page_size": 20
}
}

id and group_id are duplicate fields with the same value (kept for backwards compatibility). state is an integer — see Group States for the mapping.


POST /v3/group-builder/{company_id}/groups/​

Create a new group for a company.

Path Parameters:

  • company_id (int) - Company ID

Request Body:

{
"name": "Engineering Team",
"description": "Software engineers and developers",
"color": "#3498db"
}

Validation Rules:

  • name (required): Max 250 characters, must be unique per company
  • description (optional): Text field
  • color (optional): Hex color code (e.g., #3498db)

Response (201 Created):

{
"data": {
"id": 456,
"group_id": 456,
"name": "Engineering Team",
"description": "Software engineers and developers",
"color": "#3498db",
"state": 0,
"students_count": 0,
"created_at": "2025-01-20T10:00:00",
"updated_at": "2025-01-20T10:00:00"
}
}

PUT /v3/group-builder/{company_id}/groups/{group_id}/​

Update an existing group's details.

Path Parameters:

  • company_id (int) - Company ID
  • group_id (int) - Group ID

Request Body (all fields optional):

{
"name": "Engineering Team - Updated",
"description": "All software engineers",
"color": "#2980b9",
"state": "active"
}

State Options:

  • active - Group is active and visible
  • archived - Group is archived but not deleted
  • deleted - Group is deleted

Response:

{
"data": {
"id": 456,
"group_id": 456,
"name": "Engineering Team - Updated",
"description": "All software engineers",
"color": "#2980b9",
"state": 0,
"students_count": 25,
"created_at": "2025-01-20T10:00:00",
"updated_at": "2025-01-20T15:30:00"
}
}

DELETE /v3/group-builder/{company_id}/groups/{group_id}/​

Delete a group.

Path Parameters:

  • company_id (int) - Company ID
  • group_id (int) - Group ID

Behavior:

  • Soft-deletes the group: marks state as deleted and timestamps the name ("<original_name>-YYYYMMDDHHMMSS") so the original name can be reused.

Response:

{
"data": {
"id": 456,
"group_id": 456,
"name": "Engineering Team-20250120103000",
"description": "Software engineers and developers",
"color": "#3498db",
"state": 2,
"students_count": 25,
"created_at": "2025-01-20T10:00:00",
"updated_at": "2025-01-20T10:30:00"
}
}

GET /v3/group-builder/{company_id}/groups/{group_id}/users/​

List all users in a group.

Path Parameters:

  • company_id (int) - Company ID
  • group_id (int) - Group ID

Query Parameters:

ParameterTypeRequiredDescription
pageintNoPage number (default: 1)
page_sizeintNoItems per page (default: 20)

Example Request:

GET /v3/group-builder/123/groups/456/users/?page=1&page_size=20

Response:

{
"data": [
{
"usergroup_id": 12345,
"company_user_id": 789,
"name": "John Doe",
"email": "john.doe@company.com",
"state": "active",
"end_date": "2025-12-31",
"avatar_url": "https://static.platzi.com/media/avatars/john.jpg"
},
{
"usergroup_id": 12346,
"company_user_id": 790,
"name": "Jane Smith",
"email": "jane.smith@company.com",
"state": "active",
"end_date": "2025-12-31",
"avatar_url": "https://static.platzi.com/static/website/v2/images/avatar_default.7516253fc982.png"
}
],
"metadata": {
"count": 25,
"pages": 2,
"current_page": 1,
"page_size": 20
}
}

Response Fields:

FieldTypeDescription
usergroup_idintID of the user-group relationship row
company_user_idintCompany user ID
namestring | nullUser display name
emailstringUser email
statestringCompany-user state (e.g. active, inactive, processing)
end_datestring | nullEnd of the user's current activity window (YYYY-MM-DD)
avatar_urlstringAvatar URL (falls back to the Platzi default avatar)

POST /v3/group-builder/{company_id}/groups/{group_id}/users/​

Assign users to a group (bulk operation with partial success support).

Path Parameters:

  • company_id (int) - Company ID
  • group_id (int) - Group ID

Request Body:

{
"company_user_ids": [789, 790, 791, 792]
}

Behavior:

  • Attempts to assign all users
  • Returns successful assignments even if some fail
  • Reports errors for failed assignments
  • Skips users already in group

Response (200 OK - All successful):

{
"data": [
{ "company_user_id": 789, "usergroup_id": 12345 },
{ "company_user_id": 790, "usergroup_id": 12346 }
]
}

usergroup_id is the ID of the user-group relationship row (same value as in GET /users/).

Response (409 Conflict - Partial success):

{
"data": [
{ "company_user_id": 789, "usergroup_id": 12345 }
],
"errors": [
{
"company_user_id": 791,
"message": "User not found",
"error_code": "user_not_found"
},
{
"company_user_id": 792,
"message": "User has no linked account",
"error_code": "user_not_linked"
}
]
}

Response (400 Bad Request - All failed):

{
"errors": [
{
"company_user_id": 789,
"message": "User not found",
"error_code": "user_not_found"
},
{
"company_user_id": 790,
"message": "User not found",
"error_code": "user_not_found"
}
]
}

DELETE /v3/group-builder/{company_id}/groups/{group_id}/users/​

Remove users from a group (bulk operation with partial success support).

Path Parameters:

  • company_id (int) - Company ID
  • group_id (int) - Group ID

Query Parameters:

ParameterTypeRequiredDescription
company_user_idsstringYesComma-separated list of user IDs

Example Request:

DELETE /v3/group-builder/123/groups/456/users/?company_user_ids=789,790,791

Response (200 OK - All successful):

{
"data": [789, 790]
}

data is a list of the company_user_ids that were removed.

Response (409 Conflict - Partial success):

{
"data": [789],
"errors": [
"Company user 790 not found",
"User 791 was not in the group"
]
}

errors is a list of plain strings for this endpoint (not error objects).

Response (400 Bad Request - All failed):

{
"errors": [
"Company user 789 not found",
"Company user 790 not found"
]
}

If the company_user_ids query parameter is not a valid comma-separated integer list, the API returns 400 with the standard error envelope:

{
"errors": [
{ "message": "Invalid company_user_ids", "error_code": "bad_request" }
]
}

GET /v3/group-builder/{company_id}/groups/{group_id}/learning-paths/​

List all learning paths assigned to a group.

Path Parameters:

  • company_id (int) - Company ID
  • group_id (int) - Group ID

Example Request:

GET /v3/group-builder/123/groups/456/learning-paths/

Response:

{
"data": [
{
"id": 101,
"title": "Backend Development with Python",
"slug": "backend-python",
"badge": "achievements/badge-backend-python.png",
"state": 1,
"created_by": 0,
"private": true
},
{
"id": 102,
"title": "DevOps Fundamentals",
"slug": "devops-fundamentals",
"badge": "achievements/badge-devops.png",
"state": 1,
"created_by": 0,
"private": false
}
]
}

Response Fields:

FieldTypeDescription
idintLearning path ID
titlestringLearning path title
slugstringURL slug
badgestring | nullRelative badge path (prefix with https://static.platzi.com/media/ to get a full URL)
stateintCatalog state (only 1 is returned by this endpoint; see mapping below)
created_byintSource of the catalog entry (see mapping below)
privatebooleanWhether the learning path is private to a company

State Values:

ValueMeaning
0draft
1active
2archived
3deleted

Created By Values:

ValueMeaning
0admin (created by a Platzi admin)
1placement_test
2skill_matcher

Group States​

state is returned as an integer in responses. Use the state query parameter on the list endpoint with the name values (active, archived, deleted).

State Definitions​

NameInteger ValueDescriptionVisible in List Default
active0Group is active and visibleYes
archived1Group is archived but not deletedNo (use state=archived)
deleted2Group is soft-deletedNo (use state=deleted)

State Behavior​

ACTIVE:

  • Default state for new groups
  • Visible in default listings
  • Users can be assigned
  • Learning paths can be assigned

ARCHIVED:

  • Group is archived but still accessible
  • Not visible in default listings (requires state filter)
  • Existing users remain in group
  • Can be reactivated to ACTIVE

DELETED:

  • Soft-deleted (the group is preserved for historical reporting)
  • Name is timestamped to allow reuse
  • Not visible in default listings
  • Users remain associated (for historical data)
  • Cannot be reactivated (create a new group instead)

Bulk Operations with Partial Success​

HTTP Status Codes​

ScenarioStatus CodeResponse Structure
All successful200 OK{ data: [...] }
Partial success409 Conflict{ data: [...], errors: [...] }
All failed400 Bad Request{ errors: [...] }

The shape of errors[] differs between assign (objects: {company_user_id, message, error_code}) and remove (plain strings) — see each endpoint's example.


Error Handling​

Common Error Scenarios​

ErrorStatus CodeMessageResolution
Group not found404Group id {id} not found in company id {company_id}Verify group exists and belongs to company
Duplicate group name400Group with name '{name}' already existsUse a different name
Invalid state value400Invalid state: {state}Use active, archived, or deleted
User not in company400User {id} does not belong to company {company_id}Verify user-company relationship
User already in group409User {id} is already in group {group_id}Partial success response
User not in group409User {id} not found in group {group_id}Partial success response
Validation error400Invalid request parametersCheck request body format

Best Practices​

Group Naming​

Recommended:

  • Descriptive names: "Engineering Team", "Sales - North Region"
  • Consistent naming convention across company
  • Avoid special characters that may cause issues

Avoid:

  • Generic names: "Group 1", "Team A"
  • Very long names (> 100 characters)
  • Names with only special characters

State Management​

Active Groups:

  • Use for current, operational teams
  • Default state for new groups
  • Visible in all listings

Archived Groups:

  • Use for temporary or project-based teams that are complete
  • Preserves historical data
  • Can be reactivated if needed

Deleted Groups:

  • Use for groups that should not be reactivated
  • Name is timestamped for historical tracking
  • Consider archiving instead of deleting when possible

Bulk Operations​

Best Practices:

  • Limit batch size to 50 users per request
  • Handle partial success responses gracefully
  • Retry failed operations individually
  • Log all errors for debugging

Example Error Handling:

response = assign_users_to_group(company_id, group_id, [1, 2, 3, 4, 5])

if response.get('errors'):
# Partial success - some users failed
logger.warning(f"Partial success: {len(response['errors'])} errors")
for error in response['errors']:
logger.error(error)
# Optionally: retry failed users individually

if response.get('data'):
# Log successful assignments
logger.info(f"Successfully assigned {len(response['data'])} users")

Troubleshooting​

Groups Not Appearing in List​

Symptoms: Groups exist but don't appear in listings

Diagnosis:

  1. Check group state (may be archived or deleted)
  2. Verify company_id in query
  3. Check pagination parameters

Resolution:

  • Use state parameter to include archived/deleted groups
  • Verify correct company_id
  • Increase page_size or check other pages

Duplicate Name Error​

Symptoms: Cannot create group with existing name

Diagnosis:

  1. Check if name already exists in company
  2. Check if deleted group has same name (without timestamp)

Resolution:

  • Use a different name
  • Deleted groups have timestamped names, so the original name should be available
  • If the error persists, contact support to confirm whether a duplicate name exists

Bulk Assignment Failures​

Symptoms: All or most users fail to assign

Diagnosis:

  1. Check user IDs belong to correct company
  2. Verify group exists and is active
  3. Check if users are already in group

Resolution:

  • Validate all user IDs before batch operation
  • Use list_group_users to check current members
  • Remove already-assigned users from batch

Slow List Operations​

Symptoms: Group listing takes > 1 second

Resolution:

  • Use pagination with smaller page_size
  • Add search to narrow results
  • Cache frequently accessed responses on the client side
  • If the problem persists, contact support