Plan with AI

Get started →
Use CasesUser & Workforce ManagementTeam & Space Membership Automation
User & Workforce ManagementTeams APISpaces API

Team & Space Membership Automation

Overview

Use the Workvivo Teams and Spaces APIs to programmatically create teams, assign members, and manage space access, removing the need for manual admin configuration at scale.

In any organisation with more than a handful of teams, manually managing group memberships in Workvivo becomes unsustainable. Departments restructure, new offices open, project teams spin up and wind down, and employees move between groups constantly. Each of these changes requires someone to log into the admin panel and manually add or remove users, which is a process that doesn't scale and inevitably falls behind reality.

The Workvivo API lets you automate all of this. Create teams programmatically based on your HR system's organisational structure. Assign users to teams and spaces the moment they join a department. Grant space roles (admin, moderator, editor) based on job function. Remove users from groups when they transfer. Membership endpoints support Workvivo user IDs and user external IDs, so you can drive access from your existing systems without maintaining a separate mapping layer.

Value & Benefits

Eliminate manual group administration. Teams and space memberships stay in sync with your organisational structure automatically - no admin intervention required when employees join, move, or leave.

Ensure day-one access for new hires. New employees are added to the correct teams and spaces immediately upon provisioning, so they have access to relevant content and communities from their first day.

Keep organisational changes in sync. When departments restructure, offices open or close, or project teams form, the corresponding Workvivo groups update automatically from your source systems.

Manage space roles programmatically. Grant and revoke admin, moderator, editor, and owner roles in spaces based on job function or seniority, without relying on manual role assignment by space owners.

Support complex team structures. Use team types (Departments, Locations, Projects) to organise teams into meaningful categories, and manage membership across all of them from a single integration.

Applications

HR-driven team sync. Connect to your HRIS so that when an employee's department, location, or cost centre changes, their Workvivo team memberships update automatically to reflect the new organisational structure.

New hire onboarding automation. When a user is provisioned, automatically add them to their department team, location team, and relevant spaces, ensuring they see the right content from day one.

Project team lifecycle management. When a new project kicks off, programmatically create a team and associated space, add the project members, and grant appropriate roles. When the project ends, archive the space and remove members.

Office and location management. As new offices open or close, create or archive location-based teams and reassign employees accordingly, driven by facility management or HR data.

Role-based space access. Automatically grant space admin or editor roles to managers, team leads, or communications staff based on their role in your HR system, ensuring the right people can manage content without manual elevation requests.

Bulk restructuring. During organisational changes (mergers, department splits, reorgs), programmatically move hundreds of users between teams and spaces in a single operation rather than processing them one by one in the admin panel.

Technical Details

Before using these examples, complete Quick Start to create an app and API key and find your Base URL and Workvivo-Id.

Create a Team

curl -X POST https://api.workvivo.com/v1/teams \
  -H "Authorization: Bearer $WORKVIVO_TOKEN" \
  -H "Workvivo-Id: $WORKVIVO_ORG_ID" \
  -F "name=Dublin Engineering" \
  -F "type_id=2" \
  -F "external_id=dept-eng-dub"
{
    "data": {
        "id": 73,
        "external_id": "dept-eng-dub",
        "name": "Dublin Engineering",
        "avatar_url": "https://api.workvivo.com/img/location.png",
        "is_hidden": false,
        "permalink": "https://yourcompany.workvivo.com/directory/teams/73",
        "team_type": {
            "id": 2,
            "name": "Departments"
        }
    },
    "status": "success",
    "meta": {}
}

The type_id parameter sets the team type (e.g., Departments, Locations). Retrieve available team types via GET /v1/teams/types.

Get Team Types

curl -X GET "https://api.workvivo.com/v1/teams/types" \
  -H "Authorization: Bearer $WORKVIVO_TOKEN" \
  -H "Workvivo-Id: $WORKVIVO_ORG_ID" \
  -H "Accept: application/json"
{
    "data": [
        {
            "id": 1,
            "name": "Locations",
            "is_hidden": false
        },
        {
            "id": 2,
            "name": "Departments",
            "is_hidden": false
        }
    ],
    "status": "success",
    "meta": {
        "pagination": {
            "skip": 0,
            "take": 10,
            "total_records": 2,
            "next_page": null
        }
    }
}

Add and Remove Users from a Team

Use PATCH /v1/teams/{id}/users with ids_to_add and ids_to_remove arrays when you are passing Workvivo user IDs. Users in ids_to_add must not already be team members, and users in ids_to_remove must already be team members.

curl -X PATCH https://api.workvivo.com/v1/teams/101/users \
  -H "Authorization: Bearer $WORKVIVO_TOKEN" \
  -H "Workvivo-Id: $WORKVIVO_ORG_ID" \
  -F "ids_to_add[0]=3" \
  -F "ids_to_add[1]=8" \
  -F "ids_to_remove[0]=5"
curl -X PATCH https://api.workvivo.com/v1/teams/by-external-id/dept-eng-dub/users \
  -H "Authorization: Bearer $WORKVIVO_TOKEN" \
  -H "Workvivo-Id: $WORKVIVO_ORG_ID" \
  -F "external_ids_to_add[0]=employee-3" \
  -F "external_ids_to_add[1]=employee-8" \
  -F "external_ids_to_remove[0]=employee-5"
{
    "data": {
        "id": 101,
        "name": "Dublin Engineering",
        "external_id": "dept-eng-dub",
        "avatar_url": "https://workvivo.com/img/teams/engineering.jpg",
        "permalink": "https://yourcompany.workvivo.com/teams/101",
        "team_type": {
            "id": 2,
            "name": "Departments"
        }
    },
    "status": "success",
    "meta": {
        "users_added": 2,
        "users_removed": 1
    }
}

Create a Space

curl -X POST https://api.workvivo.com/v1/spaces \
  -H "Authorization: Bearer $WORKVIVO_TOKEN" \
  -H "Workvivo-Id: $WORKVIVO_ORG_ID" \
  -F "name=Project Alpha" \
  -F "visibility=private" \
  -F "description=Collaboration space for Project Alpha team" \
  -F "user_id=98765" \
  -F "enable_documents=true" \
  -F "enable_pages=true" \
  -F "enable_events=true"
{
    "data": {
        "id": 42,
        "parent_space_id": null,
        "name": "Project Alpha",
        "icon_url": "https://yourcompany.workvivo.com/img/illustrations/space-icon.png",
        "header_thumb_url": "https://yourcompany.workvivo.com/img/spaces/space-banner.jpg",
        "header_url": "https://yourcompany.workvivo.com/img/spaces/space-banner.jpg",
        "description": "Collaboration space for Project Alpha team",
        "visibility": "private",
        "is_external": false,
        "is_corporate": false,
        "is_mandatory": false,
        "is_read_only": false,
        "enable_news": true,
        "enable_events": true,
        "enable_documents": true,
        "enable_qa": true,
        "enable_pages": true,
        "enable_set_pages_as_default": false,
        "enable_useful_links_widget": false,
        "send_welcome_email": false,
        "enable_msteams_integration": false,
        "default_landing_page": "feed",
        "categories": [],
        "created_at": "2026-06-17T10:00:00Z",
        "updated_at": "2026-06-17T10:00:00Z",
        "permalink": "https://yourcompany.workvivo.com/spaces/42"
    },
    "status": "success",
    "meta": {}
}

Add Users to a Space with Roles

The space membership endpoint supports adding/removing users and granting/revoking roles in a single request. Use /v1/spaces/{id}/users with numeric ID fields, or /v1/spaces/by-external-id/{id}/users when the user identifiers in the request body are external IDs.

curl -X PATCH https://api.workvivo.com/v1/spaces/42/users \
  -H "Authorization: Bearer $WORKVIVO_TOKEN" \
  -H "Workvivo-Id: $WORKVIVO_ORG_ID" \
  -F "ids_to_add[0]=3" \
  -F "ids_to_add[1]=8" \
  -F "ids_to_add[2]=12" \
  -F "grant_admin_ids[0]=3" \
  -F "grant_mod_ids[0]=8"
curl -X PATCH https://api.workvivo.com/v1/spaces/by-external-id/42/users \
  -H "Authorization: Bearer $WORKVIVO_TOKEN" \
  -H "Workvivo-Id: $WORKVIVO_ORG_ID" \
  -F "external_ids_to_add[0]=employee-3" \
  -F "external_ids_to_add[1]=employee-8" \
  -F "external_ids_to_add[2]=employee-12" \
  -F "grant_admin_external_ids[0]=employee-3" \
  -F "grant_mod_external_ids[0]=employee-8"
{
    "data": {
        "id": 42,
        "name": "Project Alpha",
        "description": "Collaboration space for Project Alpha team",
        "visibility": "private",
        "created_at": "2026-06-17T10:00:00Z",
        "updated_at": "2026-06-17T10:05:00Z",
        "permalink": "https://yourcompany.workvivo.com/spaces/42"
    },
    "status": "success",
    "meta": {
        "users_added": 3,
        "users_removed": 0,
        "admins_added": 1,
        "admins_removed": 0,
        "moderators_added": 1,
        "moderators_removed": 0,
        "owners_added": 0,
        "owners_removed": 0,
        "editors_added": 0,
        "editors_removed": 0,
        "pages_editors_added": 0,
        "pages_editors_removed": 0,
        "news_editors_added": 0,
        "news_editors_removed": 0,
        "events_editors_added": 0,
        "events_editors_removed": 0,
        "documents_editors_added": 0,
        "documents_editors_removed": 0
    }
}

Available role operations on the ID-based endpoint: grant_admin_ids, revoke_admin_ids, grant_mod_ids, revoke_mod_ids, grant_owner_ids, revoke_owner_ids, grant_editor_ids, revoke_editor_ids, grant_pages_editor_ids, revoke_pages_editor_ids, grant_news_editor_ids, revoke_news_editor_ids, grant_events_editor_ids, revoke_events_editor_ids, grant_documents_editor_ids, revoke_documents_editor_ids. On the user-external-ID endpoint, use the matching _external_ids fields, for example grant_admin_external_ids and revoke_admin_external_ids.

JavaScript Integration Example

Create a Workvivo team for a department when needed, then apply membership changes using employee external IDs from your HR system.

const apiUrl = 'https://api.workvivo.com/v1';
const headers = {
    Authorization: `Bearer ${process.env.WORKVIVO_TOKEN}`,
    'Workvivo-Id': process.env.WORKVIVO_ORG_ID,
    Accept: 'application/json',
};

export async function syncDepartment(department) {
    const team =
        (await findTeam(department.external_id)) ??
        (await createTeam({
            name: department.name,
            externalId: department.external_id,
            typeId: department.workvivo_team_type_id,
        }));

    await updateTeamMembers(team.external_id, {
        add: department.employee_ids_to_add,
        remove: department.employee_ids_to_remove,
    });
}

async function findTeam(externalId) {
    const response = await fetch(
        `${apiUrl}/teams/by-external-id/${encodeURIComponent(externalId)}`,
        { headers },
    );

    if (response.status === 404) {
        return null;
    }
    if (!response.ok) {
        throw new Error(`Team lookup failed: ${response.status}`);
    }

    return (await response.json()).data;
}

async function createTeam({ name, externalId, typeId }) {
    const body = new URLSearchParams({
        name,
        external_id: externalId,
        type_id: typeId,
    });
    const response = await fetch(`${apiUrl}/teams`, {
        method: 'POST',
        headers: {
            ...headers,
            'Content-Type': 'application/x-www-form-urlencoded',
        },
        body,
    });

    if (!response.ok) {
        throw new Error(`Team creation failed: ${response.status}`);
    }

    return (await response.json()).data;
}

async function updateTeamMembers(teamExternalId, changes) {
    const body = new URLSearchParams();

    changes.add.forEach((externalId, index) => {
        body.set(`external_ids_to_add[${index}]`, externalId);
    });
    changes.remove.forEach((externalId, index) => {
        body.set(`external_ids_to_remove[${index}]`, externalId);
    });

    const response = await fetch(
        `${apiUrl}/teams/by-external-id/${encodeURIComponent(teamExternalId)}/users`,
        {
            method: 'PATCH',
            headers: {
                ...headers,
                'Content-Type': 'application/x-www-form-urlencoded',
            },
            body,
        },
    );

    if (!response.ok) {
        throw new Error(`Membership update failed: ${response.status}`);
    }
}