Bulk User Removal
curl --request POST \
--url https://www.asteragents.com/api/admin/bulkRemove \
--header 'Authorization: <authorization>' \
--header 'Content-Type: application/json' \
--data '
{
"userIds": [
{}
]
}
'import requests
url = "https://www.asteragents.com/api/admin/bulkRemove"
payload = { "userIds": [{}] }
headers = {
"Authorization": "<authorization>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<authorization>', 'Content-Type': 'application/json'},
body: JSON.stringify({userIds: [{}]})
};
fetch('https://www.asteragents.com/api/admin/bulkRemove', 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://www.asteragents.com/api/admin/bulkRemove",
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([
'userIds' => [
[
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: <authorization>",
"Content-Type: application/json"
],
]);
$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://www.asteragents.com/api/admin/bulkRemove"
payload := strings.NewReader("{\n \"userIds\": [\n {}\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<authorization>")
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://www.asteragents.com/api/admin/bulkRemove")
.header("Authorization", "<authorization>")
.header("Content-Type", "application/json")
.body("{\n \"userIds\": [\n {}\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://www.asteragents.com/api/admin/bulkRemove")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<authorization>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"userIds\": [\n {}\n ]\n}"
response = http.request(request)
puts response.read_body{
"207": {},
"400": {},
"401": {},
"403": {},
"405": {},
"success": true,
"total": 123,
"successful": 123,
"failed": 123,
"results": [
{
"userId": "<string>",
"success": true
}
],
"errors": [
{
"userId": "<string>",
"success": true,
"error": "<string>"
}
]
}Legacy Endpoints (Deprecated)
Bulk User Removal
Remove multiple users from your organization at once
POST
/
admin
/
bulkRemove
Bulk User Removal
curl --request POST \
--url https://www.asteragents.com/api/admin/bulkRemove \
--header 'Authorization: <authorization>' \
--header 'Content-Type: application/json' \
--data '
{
"userIds": [
{}
]
}
'import requests
url = "https://www.asteragents.com/api/admin/bulkRemove"
payload = { "userIds": [{}] }
headers = {
"Authorization": "<authorization>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<authorization>', 'Content-Type': 'application/json'},
body: JSON.stringify({userIds: [{}]})
};
fetch('https://www.asteragents.com/api/admin/bulkRemove', 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://www.asteragents.com/api/admin/bulkRemove",
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([
'userIds' => [
[
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: <authorization>",
"Content-Type: application/json"
],
]);
$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://www.asteragents.com/api/admin/bulkRemove"
payload := strings.NewReader("{\n \"userIds\": [\n {}\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<authorization>")
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://www.asteragents.com/api/admin/bulkRemove")
.header("Authorization", "<authorization>")
.header("Content-Type", "application/json")
.body("{\n \"userIds\": [\n {}\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://www.asteragents.com/api/admin/bulkRemove")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<authorization>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"userIds\": [\n {}\n ]\n}"
response = http.request(request)
puts response.read_body{
"207": {},
"400": {},
"401": {},
"403": {},
"405": {},
"success": true,
"total": 123,
"successful": 123,
"failed": 123,
"results": [
{
"userId": "<string>",
"success": true
}
],
"errors": [
{
"userId": "<string>",
"success": true,
"error": "<string>"
}
]
}DEPRECATED: This endpoint has been replaced by DELETE /admin/users.The new endpoint provides:
- Cleaner RESTful structure
- Better separation between users and invitations
- Consistent response format
This endpoint requires organization admin privileges. Only users with the
org:admin role can bulk remove users from their organization.Users cannot remove themselves from the organization using this endpoint. This prevents accidental lockouts.
Authentication
string
required
Bearer token for authentication. Must be from a user with
org:admin role.Body
array
required
Array of Clerk user IDs to remove from the organization (1-50 users per request)
Response
boolean
Whether all users were successfully removed
number
Total number of users requested to be removed
number
Number of users successfully removed
number
Number of users that failed to be removed
array
array
Examples
curl -X POST https://www.asteragents.com/api/admin/bulkRemove \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"userIds": [
"user_2ABC123DEF",
"user_2XYZ789GHI"
]
}'
import requests
url = "https://www.asteragents.com/api/admin/bulkRemove"
headers = {
"Authorization": "Bearer YOUR_TOKEN",
"Content-Type": "application/json"
}
data = {
"userIds": [
"user_2ABC123DEF",
"user_2XYZ789GHI",
"user_2MNO456PQR"
]
}
response = requests.post(url, headers=headers, json=data)
result = response.json()
print(f"Removed {result['successful']} users successfully")
const response = await fetch('https://www.asteragents.com/api/admin/bulkRemove', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_TOKEN',
'Content-Type': 'application/json'
},
body: JSON.stringify({
userIds: [
'user_2ABC123DEF',
'user_2XYZ789GHI'
]
})
});
const result = await response.json();
console.log(`Removed ${result.successful} users successfully`);
{
"success": true,
"total": 2,
"successful": 2,
"failed": 0,
"results": [
{
"userId": "user_2ABC123DEF",
"success": true
},
{
"userId": "user_2XYZ789GHI",
"success": true
}
]
}
{
"success": false,
"total": 3,
"successful": 2,
"failed": 1,
"results": [
{
"userId": "user_2ABC123DEF",
"success": true
},
{
"userId": "user_2XYZ789GHI",
"success": true
}
],
"errors": [
{
"userId": "user_2INVALID123",
"success": false,
"error": "User not found in organization"
}
]
}
Error Codes
object
Bad Request - Invalid request data, validation errors, or attempting to remove yourself
object
Unauthorized - Invalid or missing authentication
object
Forbidden - User is not an admin in the organization
object
Method Not Allowed - Only POST requests are accepted
object
Multi-Status - Some removals succeeded, others failed (partial success)
Workflow
Step 1: Get User IDs
First, use the Get Organization Users endpoint to retrieve user IDs:// Get all users in organization
const usersResponse = await fetch('/api/admin/getUsersInOrg', {
headers: { 'Authorization': 'Bearer ' + token }
});
const users = await usersResponse.json();
// Filter users you want to remove (e.g., by department)
// Note: publicMetadata is organization-scoped
const usersToRemove = users
.filter(user => user.publicMetadata?.department === 'marketing')
.map(user => user.id);
Step 2: Bulk Remove Users
Then use those IDs to remove users from the organization:const removeResponse = await fetch('/api/admin/bulkRemove', {
method: 'POST',
headers: {
'Authorization': 'Bearer ' + token,
'Content-Type': 'application/json'
},
body: JSON.stringify({
userIds: usersToRemove
})
});
Use Cases
Department Restructuring
Remove all users from a specific department:# Get all users
users = requests.get('/api/admin/getUsersInOrg', headers=headers).json()
# Filter by department
marketing_users = [
user['id'] for user in users
if user.get('publicMetadata', {}).get('department') == 'marketing'
]
# Remove them
response = requests.post('/api/admin/bulkRemove',
headers=headers, json={'userIds': marketing_users})
Inactive User Cleanup
Remove users who haven’t signed in recently:const cutoffDate = new Date('2023-01-01');
const inactiveUsers = users
.filter(user => {
const lastSignIn = user.lastSignInAt ? new Date(user.lastSignInAt) : null;
return !lastSignIn || lastSignIn < cutoffDate;
})
.map(user => user.id);
// Remove inactive users
await fetch('/api/admin/bulkRemove', {
method: 'POST',
headers: headers,
body: JSON.stringify({ userIds: inactiveUsers })
});
Role-Based Removal
Remove users with specific roles or metadata:# Remove all temporary contractors
temp_contractors = [
user['id'] for user in users
if user.get('publicMetadata', {}).get('role') == 'temp_contractor'
]
Features
Safe Operations: Built-in protection against self-removal and comprehensive error handling.- Self-Protection: Admins cannot accidentally remove themselves
- Batch Processing: Handle up to 50 users per request efficiently
- Detailed Results: Know exactly which users were removed and which failed
- Partial Success: Continue processing even if some removals fail
Security Notes
- Only organization admins can remove users
- Removed users lose access to the organization immediately
- Organization-scoped metadata is deleted when a user is removed from the organization
- Users can be re-invited after removal (with fresh metadata)
- Action is logged in Clerk audit logs
- Webhooks will fire for
organizationMembership.deletedevents
Limits
- Batch Size: 1-50 user IDs per request
- User ID Validation: All user IDs must be valid Clerk user identifiers
- Rate Limiting: Subject to Clerk’s API rate limits
- Self-Removal: Cannot remove your own user ID (will fail with error)
Use this endpoint in combination with Get Organization Users to build powerful user management workflows.