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