team.user.remove
Permanently removes a team member. The action is irreversible — the user record is hard-deleted and any delegated profiles assigned to them are reclaimed. The team owner cannot be removed via API.
curl --request POST \
--url https://api.manus.im/v2/team.user.remove \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"team_user_id": "123456"
}
'import requests
url = "https://api.manus.im/v2/team.user.remove"
payload = { "team_user_id": "123456" }
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({team_user_id: '123456'})
};
fetch('https://api.manus.im/v2/team.user.remove', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.manus.im/v2/team.user.remove",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'team_user_id' => '123456'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.manus.im/v2/team.user.remove"
payload := strings.NewReader("{\n \"team_user_id\": \"123456\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.manus.im/v2/team.user.remove")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"team_user_id\": \"123456\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.manus.im/v2/team.user.remove")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"team_user_id\": \"123456\"\n}"
response = http.request(request)
puts response.read_body{
"ok": true,
"request_id": "<string>",
"user": {
"email": "<string>",
"status": "USER_STATUS_ACTIVE",
"role": "TEAM_MEMBER_ROLE_OWNER",
"user_name": "<string>",
"team_user_id": "<string>",
"delegated_to": "<string>",
"delegated_profiles": [
{
"team_user_id": "<string>",
"display_name": "<string>",
"role": "TEAM_MEMBER_ROLE_OWNER",
"delegated_at": "2023-11-07T05:31:56Z"
}
],
"original_email": "<string>"
},
"cascade_affected": [
{
"team_user_id": "<string>",
"display_name": "<string>",
"action": "<string>",
"new_status": "USER_STATUS_ACTIVE"
}
]
}{
"ok": false,
"request_id": "<string>",
"error": {
"code": "<string>",
"message": "<string>"
}
}cascade_affected[]. Inspect team.user.detail first if you need to know which profiles will be reclaimed.Owner cannot be removed: Returns failed_precondition for the team owner.Equivalent to status = REMOVED: team.user.update with status: USER_STATUS_REMOVED performs the same operation by email; this endpoint is the team_user_id-keyed variant and is preferred for IDP integrations that cache the stable id.Protocols: Also callable via Connect RPC. See Protocols.Authorizations
Body
ID of the team member to remove.
1 - 64"123456"
Response
Team member removed successfully.
true
Snapshot of the removed user. status is USER_STATUS_REMOVED.
Hide child attributes
Hide child attributes
Email address. After delegation this field becomes delegate-xxx@manus.im — the pre-delegation address is preserved in original_email.
Status of a team member.
USER_STATUS_ACTIVE, USER_STATUS_INACTIVE, USER_STATUS_REMOVED Team role. TEAM_MEMBER_ROLE_OWNER is read-only and cannot be granted via API (transfer ownership in the UI). Guest members do not consume a paid seat.
TEAM_MEMBER_ROLE_OWNER, TEAM_MEMBER_ROLE_ADMIN, TEAM_MEMBER_ROLE_MEMBER, TEAM_MEMBER_ROLE_SUPER_ADMIN, TEAM_MEMBER_ROLE_GUEST Display name. Sourced from team_user_relation.Name (set via team.user.rename) when present, otherwise falls back to the underlying user's name. Omitted when neither is set.
Stable identifier for the team member, unique within the team. Use this (not email) for any subsequent profile-management call.
If this profile is currently delegated, the team_user_id of the assignee.
Profiles delegated to this user. Only populated by single-record responses (team.user.detail, team.user.update, etc.). team.user.list omits this field to avoid N+1 fan-out.
Hide child attributes
Hide child attributes
ID of the delegated profile.
Display name. Falls back to the original (pre-delegation) email when the profile has no name set.
Team role. TEAM_MEMBER_ROLE_OWNER is read-only and cannot be granted via API (transfer ownership in the UI). Guest members do not consume a paid seat.
TEAM_MEMBER_ROLE_OWNER, TEAM_MEMBER_ROLE_ADMIN, TEAM_MEMBER_ROLE_MEMBER, TEAM_MEMBER_ROLE_SUPER_ADMIN, TEAM_MEMBER_ROLE_GUEST When the delegation was created.
Pre-delegation email. Only present for currently-delegated profiles.
Profiles delegated to the removed user that were returned to the deactivated pool.
Hide child attributes
Hide child attributes
ID of the affected profile.
Display name. Falls back to the original email if the profile has no name.
Always returned_to_pool.
Status the profile now has. Always USER_STATUS_INACTIVE.
USER_STATUS_ACTIVE, USER_STATUS_INACTIVE, USER_STATUS_REMOVED curl --request POST \
--url https://api.manus.im/v2/team.user.remove \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"team_user_id": "123456"
}
'import requests
url = "https://api.manus.im/v2/team.user.remove"
payload = { "team_user_id": "123456" }
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({team_user_id: '123456'})
};
fetch('https://api.manus.im/v2/team.user.remove', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.manus.im/v2/team.user.remove",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'team_user_id' => '123456'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.manus.im/v2/team.user.remove"
payload := strings.NewReader("{\n \"team_user_id\": \"123456\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.manus.im/v2/team.user.remove")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"team_user_id\": \"123456\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.manus.im/v2/team.user.remove")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"team_user_id\": \"123456\"\n}"
response = http.request(request)
puts response.read_body{
"ok": true,
"request_id": "<string>",
"user": {
"email": "<string>",
"status": "USER_STATUS_ACTIVE",
"role": "TEAM_MEMBER_ROLE_OWNER",
"user_name": "<string>",
"team_user_id": "<string>",
"delegated_to": "<string>",
"delegated_profiles": [
{
"team_user_id": "<string>",
"display_name": "<string>",
"role": "TEAM_MEMBER_ROLE_OWNER",
"delegated_at": "2023-11-07T05:31:56Z"
}
],
"original_email": "<string>"
},
"cascade_affected": [
{
"team_user_id": "<string>",
"display_name": "<string>",
"action": "<string>",
"new_status": "USER_STATUS_ACTIVE"
}
]
}{
"ok": false,
"request_id": "<string>",
"error": {
"code": "<string>",
"message": "<string>"
}
}