curl --request POST \
--url https://app.base44.com/api/workspace/members/list \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"search": "acme.com",
"search_terms": [
"dana@acme.com",
"sam@acme.com"
],
"sort_by": "last_active",
"sort_dir": "desc",
"roles": [
"admin",
"editor"
],
"invite_statuses": [
"joined"
],
"credit_limit_set": true,
"apps_owned": {
"gte": 1,
"lte": 10
},
"agents_owned": {
"gte": 1,
"lte": 10
},
"last_active": {
"gte": "2026-09-01T00:00:00Z",
"lte": "2026-09-30T23:59:59Z"
},
"cursor": "NTA=",
"page_size": 50
}
'import requests
url = "https://app.base44.com/api/workspace/members/list"
payload = {
"search": "acme.com",
"search_terms": ["dana@acme.com", "sam@acme.com"],
"sort_by": "last_active",
"sort_dir": "desc",
"roles": ["admin", "editor"],
"invite_statuses": ["joined"],
"credit_limit_set": True,
"apps_owned": {
"gte": 1,
"lte": 10
},
"agents_owned": {
"gte": 1,
"lte": 10
},
"last_active": {
"gte": "2026-09-01T00:00:00Z",
"lte": "2026-09-30T23:59:59Z"
},
"cursor": "NTA=",
"page_size": 50
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
search: 'acme.com',
search_terms: ['dana@acme.com', 'sam@acme.com'],
sort_by: 'last_active',
sort_dir: 'desc',
roles: ['admin', 'editor'],
invite_statuses: ['joined'],
credit_limit_set: true,
apps_owned: {gte: 1, lte: 10},
agents_owned: {gte: 1, lte: 10},
last_active: {gte: '2026-09-01T00:00:00Z', lte: '2026-09-30T23:59:59Z'},
cursor: 'NTA=',
page_size: 50
})
};
fetch('https://app.base44.com/api/workspace/members/list', 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://app.base44.com/api/workspace/members/list",
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([
'search' => 'acme.com',
'search_terms' => [
'dana@acme.com',
'sam@acme.com'
],
'sort_by' => 'last_active',
'sort_dir' => 'desc',
'roles' => [
'admin',
'editor'
],
'invite_statuses' => [
'joined'
],
'credit_limit_set' => true,
'apps_owned' => [
'gte' => 1,
'lte' => 10
],
'agents_owned' => [
'gte' => 1,
'lte' => 10
],
'last_active' => [
'gte' => '2026-09-01T00:00:00Z',
'lte' => '2026-09-30T23:59:59Z'
],
'cursor' => 'NTA=',
'page_size' => 50
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"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://app.base44.com/api/workspace/members/list"
payload := strings.NewReader("{\n \"search\": \"acme.com\",\n \"search_terms\": [\n \"dana@acme.com\",\n \"sam@acme.com\"\n ],\n \"sort_by\": \"last_active\",\n \"sort_dir\": \"desc\",\n \"roles\": [\n \"admin\",\n \"editor\"\n ],\n \"invite_statuses\": [\n \"joined\"\n ],\n \"credit_limit_set\": true,\n \"apps_owned\": {\n \"gte\": 1,\n \"lte\": 10\n },\n \"agents_owned\": {\n \"gte\": 1,\n \"lte\": 10\n },\n \"last_active\": {\n \"gte\": \"2026-09-01T00:00:00Z\",\n \"lte\": \"2026-09-30T23:59:59Z\"\n },\n \"cursor\": \"NTA=\",\n \"page_size\": 50\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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://app.base44.com/api/workspace/members/list")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"search\": \"acme.com\",\n \"search_terms\": [\n \"dana@acme.com\",\n \"sam@acme.com\"\n ],\n \"sort_by\": \"last_active\",\n \"sort_dir\": \"desc\",\n \"roles\": [\n \"admin\",\n \"editor\"\n ],\n \"invite_statuses\": [\n \"joined\"\n ],\n \"credit_limit_set\": true,\n \"apps_owned\": {\n \"gte\": 1,\n \"lte\": 10\n },\n \"agents_owned\": {\n \"gte\": 1,\n \"lte\": 10\n },\n \"last_active\": {\n \"gte\": \"2026-09-01T00:00:00Z\",\n \"lte\": \"2026-09-30T23:59:59Z\"\n },\n \"cursor\": \"NTA=\",\n \"page_size\": 50\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.base44.com/api/workspace/members/list")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"search\": \"acme.com\",\n \"search_terms\": [\n \"dana@acme.com\",\n \"sam@acme.com\"\n ],\n \"sort_by\": \"last_active\",\n \"sort_dir\": \"desc\",\n \"roles\": [\n \"admin\",\n \"editor\"\n ],\n \"invite_statuses\": [\n \"joined\"\n ],\n \"credit_limit_set\": true,\n \"apps_owned\": {\n \"gte\": 1,\n \"lte\": 10\n },\n \"agents_owned\": {\n \"gte\": 1,\n \"lte\": 10\n },\n \"last_active\": {\n \"gte\": \"2026-09-01T00:00:00Z\",\n \"lte\": \"2026-09-30T23:59:59Z\"\n },\n \"cursor\": \"NTA=\",\n \"page_size\": 50\n}"
response = http.request(request)
puts response.read_body{
"members": [
{
"access_state": "granted",
"agents_owned": 1,
"agents_shared": 0,
"apps_owned": 4,
"apps_shared": 0,
"assigned_via": "direct",
"credit_limit": 500,
"credits_used": 128.5,
"email": "dana@acme.com",
"full_name": "Dana Levi",
"is_default_limit": false,
"last_active": "2026-10-03T14:12:08.512000",
"last_seen": "2026-10-05T08:41:22.004000",
"role": "editor",
"status": "active",
"user_id": "66f1c2a9b7e3d4001f8a2c55"
}
],
"next_cursor": "NTA=",
"has_more": true,
"total": 137,
"monthly_limit": 10000,
"default_member_credit_limit": 300
}{
"detail": [
{
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>"
}
]
}List workspace members
Returns one page of a workspace’s members and pending invitations, with each person’s role, credit use, credit limit, and the apps and agents they have.
Filter with roles, invite_statuses, credit_limit_set, apps_owned, agents_owned, and last_active. A member must match every filter you set. search and search_terms match part of an email, name, role, or status, and a member matches when any term does.
Set both sort_by and sort_dir to sort. Otherwise, and to break ties, joined members come before pending invitations, then by role from owner to guest, then by email. Sorting by last_active puts members who never used credits last in either direction.
To page, send the same body with cursor set to the previous response’s next_cursor, until has_more is false. total counts every match. A cursor that Base44 didn’t return starts again from the first page.
Owners and admins see everyone’s credits_used and last_seen. Other members see them only on their own row and get null for everyone else, and sorting by credits falls back to the default order for them. Active guests with a Base44 staff email aren’t listed.
credits_used, last_active, and last_seen can be that old. Changing members through Base44 starts a fresh copy, and positions in it can shift, so a page read with an older cursor can skip or repeat people. After you change members, page again from the start.This is limited to 30 requests per minute. A signed-in session has its own limit, and every personal access token for the workspace shares one. Some workspaces have a different limit.
curl --request POST \
--url https://app.base44.com/api/workspace/members/list \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"search": "acme.com",
"search_terms": [
"dana@acme.com",
"sam@acme.com"
],
"sort_by": "last_active",
"sort_dir": "desc",
"roles": [
"admin",
"editor"
],
"invite_statuses": [
"joined"
],
"credit_limit_set": true,
"apps_owned": {
"gte": 1,
"lte": 10
},
"agents_owned": {
"gte": 1,
"lte": 10
},
"last_active": {
"gte": "2026-09-01T00:00:00Z",
"lte": "2026-09-30T23:59:59Z"
},
"cursor": "NTA=",
"page_size": 50
}
'import requests
url = "https://app.base44.com/api/workspace/members/list"
payload = {
"search": "acme.com",
"search_terms": ["dana@acme.com", "sam@acme.com"],
"sort_by": "last_active",
"sort_dir": "desc",
"roles": ["admin", "editor"],
"invite_statuses": ["joined"],
"credit_limit_set": True,
"apps_owned": {
"gte": 1,
"lte": 10
},
"agents_owned": {
"gte": 1,
"lte": 10
},
"last_active": {
"gte": "2026-09-01T00:00:00Z",
"lte": "2026-09-30T23:59:59Z"
},
"cursor": "NTA=",
"page_size": 50
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
search: 'acme.com',
search_terms: ['dana@acme.com', 'sam@acme.com'],
sort_by: 'last_active',
sort_dir: 'desc',
roles: ['admin', 'editor'],
invite_statuses: ['joined'],
credit_limit_set: true,
apps_owned: {gte: 1, lte: 10},
agents_owned: {gte: 1, lte: 10},
last_active: {gte: '2026-09-01T00:00:00Z', lte: '2026-09-30T23:59:59Z'},
cursor: 'NTA=',
page_size: 50
})
};
fetch('https://app.base44.com/api/workspace/members/list', 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://app.base44.com/api/workspace/members/list",
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([
'search' => 'acme.com',
'search_terms' => [
'dana@acme.com',
'sam@acme.com'
],
'sort_by' => 'last_active',
'sort_dir' => 'desc',
'roles' => [
'admin',
'editor'
],
'invite_statuses' => [
'joined'
],
'credit_limit_set' => true,
'apps_owned' => [
'gte' => 1,
'lte' => 10
],
'agents_owned' => [
'gte' => 1,
'lte' => 10
],
'last_active' => [
'gte' => '2026-09-01T00:00:00Z',
'lte' => '2026-09-30T23:59:59Z'
],
'cursor' => 'NTA=',
'page_size' => 50
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"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://app.base44.com/api/workspace/members/list"
payload := strings.NewReader("{\n \"search\": \"acme.com\",\n \"search_terms\": [\n \"dana@acme.com\",\n \"sam@acme.com\"\n ],\n \"sort_by\": \"last_active\",\n \"sort_dir\": \"desc\",\n \"roles\": [\n \"admin\",\n \"editor\"\n ],\n \"invite_statuses\": [\n \"joined\"\n ],\n \"credit_limit_set\": true,\n \"apps_owned\": {\n \"gte\": 1,\n \"lte\": 10\n },\n \"agents_owned\": {\n \"gte\": 1,\n \"lte\": 10\n },\n \"last_active\": {\n \"gte\": \"2026-09-01T00:00:00Z\",\n \"lte\": \"2026-09-30T23:59:59Z\"\n },\n \"cursor\": \"NTA=\",\n \"page_size\": 50\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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://app.base44.com/api/workspace/members/list")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"search\": \"acme.com\",\n \"search_terms\": [\n \"dana@acme.com\",\n \"sam@acme.com\"\n ],\n \"sort_by\": \"last_active\",\n \"sort_dir\": \"desc\",\n \"roles\": [\n \"admin\",\n \"editor\"\n ],\n \"invite_statuses\": [\n \"joined\"\n ],\n \"credit_limit_set\": true,\n \"apps_owned\": {\n \"gte\": 1,\n \"lte\": 10\n },\n \"agents_owned\": {\n \"gte\": 1,\n \"lte\": 10\n },\n \"last_active\": {\n \"gte\": \"2026-09-01T00:00:00Z\",\n \"lte\": \"2026-09-30T23:59:59Z\"\n },\n \"cursor\": \"NTA=\",\n \"page_size\": 50\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.base44.com/api/workspace/members/list")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"search\": \"acme.com\",\n \"search_terms\": [\n \"dana@acme.com\",\n \"sam@acme.com\"\n ],\n \"sort_by\": \"last_active\",\n \"sort_dir\": \"desc\",\n \"roles\": [\n \"admin\",\n \"editor\"\n ],\n \"invite_statuses\": [\n \"joined\"\n ],\n \"credit_limit_set\": true,\n \"apps_owned\": {\n \"gte\": 1,\n \"lte\": 10\n },\n \"agents_owned\": {\n \"gte\": 1,\n \"lte\": 10\n },\n \"last_active\": {\n \"gte\": \"2026-09-01T00:00:00Z\",\n \"lte\": \"2026-09-30T23:59:59Z\"\n },\n \"cursor\": \"NTA=\",\n \"page_size\": 50\n}"
response = http.request(request)
puts response.read_body{
"members": [
{
"access_state": "granted",
"agents_owned": 1,
"agents_shared": 0,
"apps_owned": 4,
"apps_shared": 0,
"assigned_via": "direct",
"credit_limit": 500,
"credits_used": 128.5,
"email": "dana@acme.com",
"full_name": "Dana Levi",
"is_default_limit": false,
"last_active": "2026-10-03T14:12:08.512000",
"last_seen": "2026-10-05T08:41:22.004000",
"role": "editor",
"status": "active",
"user_id": "66f1c2a9b7e3d4001f8a2c55"
}
],
"next_cursor": "NTA=",
"has_more": true,
"total": 137,
"monthly_limit": 10000,
"default_member_credit_limit": 300
}{
"detail": [
{
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>"
}
]
}Authorizations
Personal access token, sent as Authorization: Bearer <token>.
Query Parameters
Body
One page of a members list.
Text to match, ignoring case, anywhere in a member's email, name, role, or status.
256"acme.com"
More text to match the same way as search, up to 200 terms. A member matches when any term does.
200256["dana@acme.com", "sam@acme.com"]
Column to sort by: member (name, or email when there's no name), credits (credits_used), apps and agents (owned plus shared), last_active, or role (owner, admin, editor, viewer, guest). Needs sort_dir.
member, credits, apps, agents, last_active, role "last_active"
Sort direction. Needs sort_by.
asc, desc "desc"
Only members with one of these roles: owner, admin, editor, viewer, or guest.
20["admin", "editor"]
Only people in one of these states: joined, pending (invited and not yet joined), or expired (the invitation lapsed).
3joined, pending, expired ["joined"]
true for only members with their own credit limit, false for only members without one. A member on the workspace default counts as not having their own.
true
Only members whose apps_owned plus apps_shared is in this range.
Show child attributes
Show child attributes
Only members whose agents_owned plus agents_shared is in this range.
Show child attributes
Show child attributes
Only members whose last_active is in this range. Members who never used credits don't match.
Show child attributes
Show child attributes
next_cursor from the previous page. Leave it out for the first page.
256"NTA="
How many people to return, 1 to 100. Defaults to 50.
1 <= x <= 10050
Response
One page of members.
One page of workspace members.
The people on this page.
Show child attributes
Show child attributes
[ { "access_state": "granted", "agents_owned": 1, "agents_shared": 0, "apps_owned": 4, "apps_shared": 0, "assigned_via": "direct", "credit_limit": 500, "credits_used": 128.5, "email": "dana@acme.com", "full_name": "Dana Levi", "is_default_limit": false, "last_active": "2026-10-03T14:12:08.512000", "last_seen": "2026-10-05T08:41:22.004000", "role": "editor", "status": "active", "user_id": "66f1c2a9b7e3d4001f8a2c55" } ]
Pass as cursor to get the next page. null on the last page.
"NTA="
true when there's another page.
true
Number of people matching the filters, across all pages.
137
The workspace's monthly credits, or null when they're unlimited.
10000
The workspace's default member credit limit, or null when none is set.
300
Was this page helpful?