Skip to main content

Overview

The /users endpoint retrieves a paginated list of users with optional filtering by recipe, email, phone number, or third-party provider. This endpoint is tenant-specific and supports searching across multiple authentication methods. Key Features:
  • Pagination with customizable limits
  • Filter by authentication recipe (emailpassword, passwordless, thirdparty, etc.)
  • Search by email, phone number, or provider
  • Sort by join time (ascending or descending)
  • User ID mapping support
  • Multitenancy support

Endpoint

GET /users
Base URL: http://localhost:3567 Authentication: Requires API key

Request

Headers

api-key
string
required
Your SuperTokens API key
cdi-version
string
CDI version (e.g., “5.4”)

Query Parameters

includeRecipeIds
string
Comma-separated list of recipe IDs to include. Valid values: emailpassword, passwordless, thirdparty.Example: emailpassword,thirdparty
limit
integer
default:"100"
Maximum number of users to return. Must be between 1 and 1000 (or 500 when searching).
paginationToken
string
Base64-encoded token for pagination. Use the nextPaginationToken from the previous response.
timeJoinedOrder
string
default:"ASC"
Sort order for users. Valid values: ASC or DESC.
email
string
Search for users by email address. Supports multiple emails separated by semicolons.Example: [email protected];[email protected]
phone
string
Search for users by phone number. Supports multiple phone numbers separated by semicolons.Example: +1234567890;+0987654321
provider
string
Search for users by third-party provider. Supports multiple providers separated by semicolons.Example: google;github

Request Body

None.

Response

Success Response

Status Code: 200 OK Content-Type: application/json Body:
{
  "status": "OK",
  "users": [
    {
      "id": "user-id-1",
      "timeJoined": 1234567890000,
      "isPrimaryUser": true,
      "emails": ["[email protected]"],
      "phoneNumbers": ["+1234567890"],
      "thirdParty": [],
      "loginMethods": [
        {
          "recipeId": "emailpassword",
          "recipeUserId": "recipe-user-id",
          "timeJoined": 1234567890000,
          "verified": true,
          "email": "[email protected]"
        }
      ],
      "tenantIds": ["public"]
    }
  ],
  "nextPaginationToken": "eyJwYWdlIjoxfQ=="
}
status
string
required
Response status - always "OK" on success
users
array
required
Array of user objects. For CDI versions < 4.0, returns a different format with recipe wrapper.
nextPaginationToken
string
Token for fetching the next page of results. Omitted if there are no more users.

User Object (CDI >= 4.0)

id
string
User’s unique identifier (external ID if mapping exists)
timeJoined
number
Unix timestamp in milliseconds when user joined
isPrimaryUser
boolean
Whether this is a primary user account
emails
array
Array of email addresses associated with the user
phoneNumbers
array
Array of phone numbers associated with the user
thirdParty
array
Array of third-party authentication providers
loginMethods
array
Array of login methods (authentication recipes) for this user
tenantIds
array
Array of tenant IDs the user belongs to (CDI >= 3.0)

Error Response

Status Code: 400 Bad Request
{
  "message": "timeJoinedOrder can be either ASC OR DESC"
}
Common Error Messages:
  • "Unknown recipe ID: {recipeId}" - Invalid recipe ID provided
  • "max limit allowed is 1000" - Limit exceeds maximum
  • "limit must a positive integer with min value 1" - Invalid limit value
  • "invalid pagination token" - Malformed or expired pagination token

Examples

Basic Usage

curl -X GET "http://localhost:3567/users?limit=10" \
  -H "api-key: your_api_key_here"

Filter by Recipe

curl -X GET "http://localhost:3567/users?includeRecipeIds=emailpassword,thirdparty" \
  -H "api-key: your_api_key_here"

Search by Email

curl -X GET "http://localhost:3567/[email protected]" \
  -H "api-key: your_api_key_here"
curl -X GET "http://localhost:3567/[email protected];[email protected]" \
  -H "api-key: your_api_key_here"

Search by Phone

curl -X GET "http://localhost:3567/users?phone=%2B1234567890" \
  -H "api-key: your_api_key_here"

Search by Provider

curl -X GET "http://localhost:3567/users?provider=google" \
  -H "api-key: your_api_key_here"

Pagination

# First page
curl -X GET "http://localhost:3567/users?limit=100" \
  -H "api-key: your_api_key_here"

# Next page using token from response
curl -X GET "http://localhost:3567/users?limit=100&paginationToken=eyJwYWdlIjoxfQ==" \
  -H "api-key: your_api_key_here"

Sort Descending

curl -X GET "http://localhost:3567/users?timeJoinedOrder=DESC" \
  -H "api-key: your_api_key_here"

JavaScript (Node.js)

const response = await fetch('http://localhost:3567/users?limit=50', {
  headers: {
    'api-key': 'your_api_key_here',
    'cdi-version': '5.4'
  }
});

const data = await response.json();
console.log(`Found ${data.users.length} users`);

if (data.nextPaginationToken) {
  console.log('More users available');
}

Python

import requests

response = requests.get(
    'http://localhost:3567/users',
    params={
        'limit': 50,
        'includeRecipeIds': 'emailpassword',
        'timeJoinedOrder': 'DESC'
    },
    headers={
        'api-key': 'your_api_key_here'
    }
)

data = response.json()
for user in data['users']:
    print(f"User: {user['id']} - {user.get('emails', [])}")

Paginate Through All Users

async function getAllUsers() {
  const allUsers = [];
  let paginationToken = null;
  
  do {
    const params = new URLSearchParams({ limit: '500' });
    if (paginationToken) {
      params.append('paginationToken', paginationToken);
    }
    
    const response = await fetch(`http://localhost:3567/users?${params}`, {
      headers: { 'api-key': 'your_api_key_here' }
    });
    
    const data = await response.json();
    allUsers.push(...data.users);
    paginationToken = data.nextPaginationToken;
  } while (paginationToken);
  
  return allUsers;
}

Implementation Details

Search Tag Normalization

Email, phone, and provider search tags are normalized:
  • Converted to lowercase
  • Trimmed of whitespace
  • Empty tags are filtered out
Source: View source

Limit Restrictions

When searching (email, phone, or provider filters), the maximum limit may be lower than the default 1000 to ensure reasonable response times. Source: View source

User ID Mapping

If user ID mapping is enabled, the response will contain external user IDs instead of internal SuperTokens IDs. Source: View source

Version Compatibility

The response format varies based on CDI version:
  • < 3.0: No tenantIds field
  • < 4.0: Users wrapped in {recipeId, user} objects
  • >= 4.0: Direct user objects with loginMethods
  • >= 5.3: Enhanced user metadata
Source: View source

Get User by ID

Retrieve a specific user by ID

User Count

Get total number of users

Search by Account Info

Advanced user search by account information

API Overview

Learn about pagination and error handling

Additional User Endpoints

Get User by ID

GET /user/id?userId={userId}
Retrieve a single user by their ID. Response:
{
  "status": "OK",
  "user": { /* user object */ }
}
Or if user not found:
{
  "status": "UNKNOWN_USER_ID_ERROR"
}

Users Count

GET /users/count?includeRecipeIds={recipes}&includeAllTenants={boolean}
Get the total count of users, optionally filtered by recipe. Response:
{
  "status": "OK",
  "count": 1234
}

Search by Account Info

GET /users/by-accountinfo?email={email}&phoneNumber={phone}&thirdPartyId={id}&thirdPartyUserId={userId}&doUnionOfAccountInfo={boolean}
Search for users by specific account information with union or intersection logic. Response:
{
  "status": "OK",
  "users": [ /* array of user objects */ ]
}

Best Practices

Use pagination tokens for large user bases instead of increasing the limit. This provides better performance and more reliable results.
Search parameters (email, phone, provider) are case-insensitive and normalized. Always provide them in a consistent format for predictable results.
Performance Tips:
  • Keep limits reasonable (100-500) for faster responses
  • Use recipe filters to narrow down results
  • Cache pagination tokens for consistent page navigation
  • Consider tenant-specific queries for multitenancy setups
Security Considerations:
  • Always use API keys for authentication
  • Don’t expose user lists publicly
  • Implement additional access controls in your application layer
  • Be mindful of user privacy when logging or displaying user data

Build docs developers (and LLMs) love