HRIS Integration - Users API Guide
Complete guide for external HRIS systems integrating with MangoApps to retrieve user and employee data in bulk. This API enables seamless synchronization of employee information between MangoApps and external HRIS platforms.
Target Audience: Developers building HRIS integrations with MangoApps
Prerequisites: Admin access to create API tokens with read:users scope
API Version: v1
Overview
What is the HRIS Users API?
The HRIS Users API provides external HRIS systems with programmatic access to retrieve user and employee data from MangoApps. This enables:
- Bulk User Retrieval: Fetch multiple users with pagination and filtering
- Individual User Lookup: Find specific users by unique identifier (UID) or email
- Incremental Synchronization: Retrieve only users updated since a specific timestamp
- Comprehensive Data: Access complete employee profiles including employment details, manager relationships, and organizational data
- Real-time Updates: Subscribe to webhooks for user lifecycle events
Why Use This API?
- Efficient Synchronization: Bulk retrieval with pagination handles large user bases
- Definitive UID: Uses
mango_employee_id(E1234567 format) as primary identifier - Business Isolation: Automatically scoped to your business - no cross-business data leakage
- Audit Trail: All API access is logged for security and compliance
- Rate Limited: Built-in rate limiting protects system performance
- Webhook Support: Real-time notifications for user changes
Key Features
- âś… Bulk Retrieval: Get multiple users with pagination (up to 100 per page)
- âś… Multiple Lookup Methods: Find users by UID (
mango_employee_id) or email - âś… Advanced Filtering: Filter by active status, department, employment status, search terms
- âś… Incremental Sync:
updated_afterparameter for efficient synchronization - âś… Soft Deletion Support: Include deleted users for compliance/auditing
- âś… Sorting: Sort by name, created_at, updated_at
- âś… Webhooks: Real-time notifications for user.created, user.updated, user.activated, user.deactivated, user.deleted
Complete API Call Flow
High-Level Flow Diagram
Step-by-Step Implementation
Step 1: Create an API Token
Prerequisites:
- Admin access to MangoApps
- Understanding of required permission scopes
Process:
- Navigate to Admin Interface
- Go to Admin → API → Tokens
- Click Create API Token (or Create Service Account Token for system integrations)
- Configure Token Settings
- Name: Descriptive name (e.g., “HRIS Integration - User Sync”)
- Scopes: Select
adminorread:usersscopeadmin: Full access including user managementread:users: Read-only access to user data (recommended for HRIS integrations)
- Service Account: Check this box for system-to-system integrations (optional but recommended)
- Expiration: Set appropriate expiration date
- Business: Automatically set to your current business
- Save and Copy Token
- Click Create Token
- IMPORTANT: Copy the Token immediately
- This value is shown only once and cannot be retrieved later
- If using a service account, also copy the Secret
Example Response:
{
"token": "abc123def456ghi789jkl012mno345pqr678",
"secret": "sec_xyz789uvw456rst123", // Only for service accounts
"name": "HRIS Integration - User Sync",
"scopes": ["read:users"],
"expires_at": "2026-01-15T10:30:00Z"
}
Security Notes:
- Store tokens securely (environment variables, secret managers)
- Never commit tokens to version control
- Use different tokens for different environments (dev/staging/prod)
- Rotate tokens periodically (every 6-12 months)
Step 2: Retrieve Users in Bulk
Endpoint: GET /api/v1/users
Authentication: Use your API token
Request Headers:
Authorization: Bearer YOUR_API_TOKEN
Content-Type: application/json
Accept: application/json
Query Parameters:
| Parameter | Type | Required | Description | Default | Example |
|---|---|---|---|---|---|
page |
integer | No | Page number for pagination | 1 | ?page=2 |
per_page |
integer | No | Number of users per page (max 100) | 25 | ?per_page=50 |
active |
boolean | No | Filter by active status | all | ?active=true |
search |
string | No | Search by name or email | - | ?search=john |
department |
string | No | Filter by department name | - | ?department=Engineering |
employment_status |
string | No | Filter by employment status | - | ?employment_status=full_time |
updated_after |
datetime | No | Only users updated after this time (ISO 8601) | - | ?updated_after=2025-11-17T00:00:00Z |
include_deleted |
boolean | No | Include soft-deleted users | false | ?include_deleted=true |
sort_by |
string | No | Sort field: name, created_at, updated_at |
created_at |
?sort_by=name |
sort_order |
string | No | Sort direction: asc, desc |
desc |
?sort_order=asc |
Example Request (cURL):
curl -X GET "https://your-domain.com/api/v1/users?page=1&per_page=50&active=true" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json"
Example Response:
{
"users": [
{
"uid": "E1000001",
"id": 1753,
"email": "alice.anderson@example.com",
"first_name": "Alice",
"last_name": "Anderson",
"full_name": "Alice Anderson",
"active": true,
"job_title": "Senior Engineer",
"department": "Engineering",
"organizational_role": "Staff",
"hire_date": "2020-01-15",
"original_hire_date": "2020-01-15",
"employment_status": "full_time",
"employee_type": "Full-Time",
"phone": "+1-415-555-2847",
"manager": {
"uid": "E1000002",
"email": "manager@example.com",
"full_name": "Manager Name"
},
"locations": ["San Francisco Office"],
"termination_date": null,
"termination_type": null,
"created_at": "2025-10-13T23:23:24Z",
"updated_at": "2025-11-14T18:17:29Z",
"last_activity_at": "2025-11-14T18:17:29Z"
}
],
"meta": {
"total_count": 37,
"total_pages": 1,
"current_page": 1,
"per_page": 50
}
}
Response Fields:
Each user object includes:
uid: Unique mango_employee_id (E1234567 format) - Primary identifier for HRIS systemsid: Internal MangoApps user ID (integer)email: User’s email addressfirst_name,last_name,full_name: Name fieldsactive: Boolean indicating if user is activejob_title: Job position/titledepartment: Department nameorganizational_role: Role (Administrator, Manager, Staff, etc.)hire_date: Original hire dateoriginal_hire_date: Original hire date (if different from hire_date)employment_status: full_time, part_time, contractor, etc.employee_type: Full-Time, Part-Time, Contractor, etc.phone: Phone numbermanager: Manager information (if applicable)locations: Array of location namestermination_date: Termination date (if terminated)termination_type: Termination type (if terminated)created_at,updated_at,last_activity_at: Timestamps
Pagination:
The meta object provides pagination information:
total_count: Total number of users matching the querytotal_pages: Total number of pagescurrent_page: Current page numberper_page: Number of users per page
Example: Pagination Loop
page = 1
all_users = []
while True:
response = requests.get(
f'{base_url}/api/v1/users',
headers={'Authorization': f'Bearer {token}'},
params={'page': page, 'per_page': 50}
)
data = response.json()
all_users.extend(data['users'])
if page >= data['meta']['total_pages']:
break
page += 1
Step 3: Retrieve Individual User by UID
Endpoint: GET /api/v1/users/:uid
Authentication: Use your API token
Parameters:
uid: The mango_employee_id (e.g., “E1000001”) - Primary identifier
Example Request:
curl -X GET "https://your-domain.com/api/v1/users/E1000001" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json"
Example Response:
{
"user": {
"uid": "E1000001",
"id": 1753,
"email": "alice.anderson@example.com",
"first_name": "Alice",
"last_name": "Anderson",
"full_name": "Alice Anderson",
"active": true,
"job_title": "Senior Engineer",
"department": "Engineering",
"organizational_role": "Staff",
"hire_date": "2020-01-15",
"employment_status": "full_time",
"employee_type": "Full-Time",
"phone": "+1-415-555-2847",
"manager": {
"uid": "E1000002",
"email": "manager@example.com",
"full_name": "Manager Name",
"job_title": "Engineering Manager"
},
"direct_reports_count": 5,
"locations": [
{
"name": "San Francisco Office",
"address": "123 Main St, San Francisco, CA"
}
],
"organizational_department": {
"name": "Engineering",
"code": "ENG"
},
"flsa_status": "exempt",
"worker_classification": "employee",
"time_zone": "America/Los_Angeles",
"external_employee_id": "EMP-12345",
"skills_count": 8,
"certifications_count": 3,
"termination_date": null,
"termination_type": null,
"created_at": "2025-10-13T23:23:24Z",
"updated_at": "2025-11-14T18:17:29Z",
"last_activity_at": "2025-11-14T18:17:29Z"
}
}
Additional Fields in Detail Response:
manager: Detailed manager information (not just basic info)direct_reports_count: Number of direct reportslocations: Detailed location objects with addressesorganizational_department: Detailed department informationflsa_status: FLSA exemption statusworker_classification: Worker classificationtime_zone: User’s timezoneexternal_employee_id: External system’s employee ID (if set)skills_count: Number of skillscertifications_count: Number of certifications
Error Responses:
404 Not Found - User Not Found:
{
"error": {
"code": "user_not_found",
"message": "User with UID 'E9999999' not found in current business"
}
}
Step 4: Retrieve Individual User by Email
Endpoint: GET /api/v1/users/by_email/:email
Authentication: Use your API token
Parameters:
email: The user’s email address
Example Request:
curl -X GET "https://your-domain.com/api/v1/users/by_email/alice.anderson@example.com" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json"
Example Response:
Same format as individual user lookup by UID (detailed response).
Error Responses:
404 Not Found - User Not Found:
{
"error": {
"code": "user_not_found",
"message": "User with email 'nonexistent@example.com' not found in current business"
}
}
Complete Integration Example
Python Example
import requests
import os
from datetime import datetime, timedelta
from typing import List, Dict, Optional
class MangoAppsHRISClient:
def __init__(self, base_url: str, api_token: str):
"""
Initialize HRIS API client
Args:
base_url: MangoApps API base URL (e.g., 'https://your-domain.com')
api_token: API token with 'read:users' scope
"""
self.base_url = base_url.rstrip('/')
self.api_token = api_token
self.headers = {
'Authorization': f'Bearer {api_token}',
'Content-Type': 'application/json',
'Accept': 'application/json'
}
def get_all_users(self,
active_only: bool = True,
per_page: int = 50,
include_deleted: bool = False) -> List[Dict]:
"""
Retrieve all users with pagination
Args:
active_only: Only return active users
per_page: Number of users per page (max 100)
include_deleted: Include soft-deleted users
Returns:
List of user dictionaries
"""
all_users = []
page = 1
while True:
params = {
'page': page,
'per_page': min(per_page, 100), # Cap at 100
'active': 'true' if active_only else None,
'include_deleted': 'true' if include_deleted else None
}
# Remove None values
params = {k: v for k, v in params.items() if v is not None}
response = requests.get(
f'{self.base_url}/api/v1/users',
headers=self.headers,
params=params
)
response.raise_for_status()
data = response.json()
all_users.extend(data['users'])
# Check if we've reached the last page
if page >= data['meta']['total_pages']:
break
page += 1
return all_users
def get_user_by_uid(self, uid: str) -> Dict:
"""
Retrieve a single user by mango_employee_id (UID)
Args:
uid: mango_employee_id (e.g., 'E1000001')
Returns:
User dictionary with detailed information
"""
response = requests.get(
f'{self.base_url}/api/v1/users/{uid}',
headers=self.headers
)
response.raise_for_status()
return response.json()['user']
def get_user_by_email(self, email: str) -> Dict:
"""
Retrieve a single user by email address
Args:
email: User's email address
Returns:
User dictionary with detailed information
"""
response = requests.get(
f'{self.base_url}/api/v1/users/by_email/{email}',
headers=self.headers
)
response.raise_for_status()
return response.json()['user']
def get_users_updated_since(self,
since: datetime,
per_page: int = 50) -> List[Dict]:
"""
Retrieve users updated since a specific timestamp (incremental sync)
Args:
since: Datetime object for the cutoff time
per_page: Number of users per page
Returns:
List of user dictionaries updated since the timestamp
"""
all_users = []
page = 1
# Format datetime as ISO 8601
updated_after = since.strftime('%Y-%m-%dT%H:%M:%SZ')
while True:
params = {
'page': page,
'per_page': min(per_page, 100),
'updated_after': updated_after
}
response = requests.get(
f'{self.base_url}/api/v1/users',
headers=self.headers,
params=params
)
response.raise_for_status()
data = response.json()
all_users.extend(data['users'])
if page >= data['meta']['total_pages']:
break
page += 1
return all_users
def search_users(self,
search_term: str,
department: Optional[str] = None,
employment_status: Optional[str] = None) -> List[Dict]:
"""
Search users by name or email with optional filters
Args:
search_term: Search query (searches name and email)
department: Filter by department name
employment_status: Filter by employment status
Returns:
List of matching user dictionaries
"""
params = {
'search': search_term,
'per_page': 100
}
if department:
params['department'] = department
if employment_status:
params['employment_status'] = employment_status
response = requests.get(
f'{self.base_url}/api/v1/users',
headers=self.headers,
params=params
)
response.raise_for_status()
return response.json()['users']
# Usage Example
if __name__ == '__main__':
# Initialize client
client = MangoAppsHRISClient(
base_url='https://your-domain.com',
api_token=os.getenv('MANGOOPS_API_TOKEN')
)
# Example 1: Get all active users
print("Fetching all active users...")
all_users = client.get_all_users(active_only=True)
print(f"Found {len(all_users)} active users")
# Example 2: Get user by UID
print("\nFetching user by UID...")
user = client.get_user_by_uid('E1000001')
print(f"User: {user['full_name']} ({user['email']})")
# Example 3: Incremental sync (users updated in last 24 hours)
print("\nFetching users updated in last 24 hours...")
since = datetime.utcnow() - timedelta(days=1)
updated_users = client.get_users_updated_since(since)
print(f"Found {len(updated_users)} updated users")
# Example 4: Search users
print("\nSearching users...")
results = client.search_users('john', department='Engineering')
print(f"Found {len(results)} matching users")
JavaScript/Node.js Example
const axios = require('axios');
class MangoAppsHRISClient {
constructor(baseUrl, apiToken) {
this.baseUrl = baseUrl.replace(/\/$/, '');
this.apiToken = apiToken;
this.headers = {
'Authorization': `Bearer ${apiToken}`,
'Content-Type': 'application/json',
'Accept': 'application/json'
};
}
async getAllUsers(options = {}) {
const {
activeOnly = true,
perPage = 50,
includeDeleted = false
} = options;
const allUsers = [];
let page = 1;
while (true) {
const params = {
page,
per_page: Math.min(perPage, 100),
...(activeOnly && { active: 'true' }),
...(includeDeleted && { include_deleted: 'true' })
};
const response = await axios.get(
`${this.baseUrl}/api/v1/users`,
{ headers: this.headers, params }
);
const { users, meta } = response.data;
allUsers.push(...users);
if (page >= meta.total_pages) break;
page++;
}
return allUsers;
}
async getUserByUID(uid) {
const response = await axios.get(
`${this.baseUrl}/api/v1/users/${uid}`,
{ headers: this.headers }
);
return response.data.user;
}
async getUserByEmail(email) {
const response = await axios.get(
`${this.baseUrl}/api/v1/users/by_email/${email}`,
{ headers: this.headers }
);
return response.data.user;
}
async getUsersUpdatedSince(since, perPage = 50) {
const allUsers = [];
let page = 1;
const updatedAfter = since.toISOString();
while (true) {
const response = await axios.get(
`${this.baseUrl}/api/v1/users`,
{
headers: this.headers,
params: {
page,
per_page: Math.min(perPage, 100),
updated_after: updatedAfter
}
}
);
const { users, meta } = response.data;
allUsers.push(...users);
if (page >= meta.total_pages) break;
page++;
}
return allUsers;
}
}
// Usage Example
(async () => {
const client = new MangoAppsHRISClient(
'https://your-domain.com',
process.env.MANGOOPS_API_TOKEN
);
// Get all active users
const users = await client.getAllUsers({ activeOnly: true });
console.log(`Found ${users.length} active users`);
// Get user by UID
const user = await client.getUserByUID('E1000001');
console.log(`User: ${user.full_name} (${user.email})`);
// Incremental sync
const since = new Date();
since.setDate(since.getDate() - 1);
const updatedUsers = await client.getUsersUpdatedSince(since);
console.log(`Found ${updatedUsers.length} updated users`);
})();
Webhooks for Real-Time Updates
Setting Up Webhooks
Webhooks provide real-time notifications when user data changes in MangoApps. This eliminates the need for polling and enables immediate synchronization.
1. Create a Webhook
Navigate to Admin → API → Webhooks → New Webhook
Configuration:
- Name: Descriptive name (e.g., “HRIS User Sync Webhook”)
- URL: Your webhook endpoint URL
- Event Types: Select user-related events:
user.created- New user createduser.updated- User information updateduser.activated- User activateduser.deactivated- User deactivateduser.deleted- User soft-deleted
- Active: Enable the webhook
2. Webhook Payload Format
user.created Event:
{
"event": "user.created",
"timestamp": "2025-11-18T15:30:00Z",
"data": {
"uid": "E1000001",
"user": {
"uid": "E1000001",
"email": "alice.anderson@example.com",
"first_name": "Alice",
"last_name": "Anderson",
"full_name": "Alice Anderson",
"active": true,
"job_title": "Senior Engineer",
"employment_status": "full_time",
"employee_type": "Full-Time"
}
}
}
user.updated Event:
{
"event": "user.updated",
"timestamp": "2025-11-18T15:30:00Z",
"data": {
"uid": "E1000001",
"changes": ["job_title", "department"],
"user": {
"uid": "E1000001",
"email": "alice.anderson@example.com",
"first_name": "Alice",
"last_name": "Anderson",
"full_name": "Alice Anderson",
"active": true,
"job_title": "Engineering Manager",
"employment_status": "full_time",
"employee_type": "Full-Time"
}
}
}
user.deleted Event:
{
"event": "user.deleted",
"timestamp": "2025-11-18T15:30:00Z",
"data": {
"uid": "E1000001",
"user": {
"uid": "E1000001",
"email": "alice.anderson@example.com",
"first_name": "Alice",
"last_name": "Anderson",
"full_name": "Alice Anderson"
},
"deleted_at": "2025-11-18T15:30:00Z",
"deleted_by": "admin@example.com"
}
}
3. Webhook Security
Webhooks include a signature header for verification:
X-MangoApps-Signature: sha256=abc123def456...
Verify the signature using your webhook secret to ensure the request is authentic.
4. Webhook Retry Logic
MangoApps automatically retries failed webhook deliveries with exponential backoff:
- 1 minute
- 5 minutes
- 15 minutes
- 1 hour
- 4 hours
After 5 consecutive failures, the webhook is automatically deactivated.
Common Use Cases
Use Case 1: Initial User Synchronization
Scenario: Sync all users from MangoApps to your HRIS system on first integration
# Get all active users
client = MangoAppsHRISClient(base_url, api_token)
all_users = client.get_all_users(active_only=True)
# Process each user
for user in all_users:
# Use user['uid'] as the primary identifier
sync_user_to_hris(user['uid'], user)
print(f"Synced user: {user['full_name']} ({user['uid']})")
Use Case 2: Incremental Synchronization
Scenario: Sync only users updated since last sync (efficient for regular syncs)
# Get last sync timestamp from your system
last_sync = get_last_sync_timestamp()
# Get users updated since last sync
client = MangoAppsHRISClient(base_url, api_token)
updated_users = client.get_users_updated_since(last_sync)
# Process updates
for user in updated_users:
update_user_in_hris(user['uid'], user)
print(f"Updated user: {user['full_name']} ({user['uid']})")
# Update last sync timestamp
update_last_sync_timestamp(datetime.utcnow())
Use Case 3: User Lookup by Email
Scenario: Find a user in MangoApps when you only have their email address
client = MangoAppsHRISClient(base_url, api_token)
try:
user = client.get_user_by_email('alice.anderson@example.com')
print(f"Found user: {user['full_name']} (UID: {user['uid']})")
# Use user['uid'] for future lookups
except requests.exceptions.HTTPError as e:
if e.response.status_code == 404:
print("User not found")
else:
raise
Use Case 4: Department-Based Filtering
Scenario: Sync users from a specific department
client = MangoAppsHRISClient(base_url, api_token)
# Get all users in Engineering department
response = requests.get(
f'{client.base_url}/api/v1/users',
headers=client.headers,
params={
'department': 'Engineering',
'per_page': 100,
'active': 'true'
}
)
engineering_users = response.json()['users']
print(f"Found {len(engineering_users)} Engineering users")
Use Case 5: Webhook-Based Real-Time Sync
Scenario: Use webhooks for immediate synchronization when users change
from flask import Flask, request, jsonify
import hmac
import hashlib
app = Flask(__name__)
WEBHOOK_SECRET = os.getenv('WEBHOOK_SECRET')
@app.route('/webhook/mangoops', methods=['POST'])
def mangoapps_webhook():
# Verify signature
signature = request.headers.get('X-MangoApps-Signature')
if not verify_signature(request.data, signature):
return jsonify({'error': 'Invalid signature'}), 401
event = request.json
if event['event'] == 'user.created':
# New user - sync to HRIS
sync_user_to_hris(event['data']['uid'], event['data']['user'])
elif event['event'] == 'user.updated':
# User updated - update in HRIS
update_user_in_hris(event['data']['uid'], event['data']['user'])
elif event['event'] == 'user.deleted':
# User deleted - mark as deleted in HRIS
mark_user_deleted_in_hris(event['data']['uid'])
return jsonify({'status': 'ok'}), 200
def verify_signature(payload, signature):
expected = hmac.new(
WEBHOOK_SECRET.encode(),
payload,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(f'sha256={expected}', signature)
Security Best Practices
API Token Security
- Use Least Privilege: Only grant
read:usersscope if that’s all you need - Separate Environments: Use different tokens for dev/staging/prod
- Regular Rotation: Rotate tokens periodically (every 6-12 months)
- Secure Storage: Store tokens in environment variables or secret managers
- Monitor Usage: Regularly review API access logs in Admin → API → Audit Logs
API Call Security
- HTTPS Only: Always use HTTPS for API calls
- Error Handling: Don’t expose tokens in error messages
- Rate Limiting: Respect API rate limits (100 requests/hour for bulk endpoints)
- Request Validation: Validate all input before making API calls
- Logging: Log API calls but never log tokens
Webhook Security
- Verify Signatures: Always verify webhook signatures
- HTTPS Endpoints: Use HTTPS for webhook endpoints
- Idempotency: Handle duplicate webhook deliveries gracefully
- Timeout Handling: Set appropriate timeouts for webhook processing
- Error Handling: Return proper HTTP status codes
Troubleshooting
Issue: “Invalid or expired authentication token” Error
Problem: Getting 401 error when making API calls
Solution:
- Verify your API token is correct
- Check that token hasn’t expired
- Ensure token has
read:usersoradminscope - Verify you’re using
Authorization: Bearer TOKENheader format
Issue: “Insufficient scope” Error
Problem: Getting 403 error about insufficient scope
Solution:
- Verify API token has
read:usersoradminscope - Create new API token with correct scopes
- Check token configuration in Admin → API → Tokens
Issue: “User not found” Error
Problem: Getting 404 error when looking up user
Solution:
- Verify user exists in your business
- Check that user belongs to the same business as API token
- Ensure UID format is correct (E1234567)
- Verify email address is correct and user exists
Issue: Empty Results from Bulk Retrieval
Problem: Getting empty users array
Solution:
- Check that your business has users
- Verify filters aren’t too restrictive
- Try removing filters to see all users
- Check
include_deletedparameter if looking for deleted users
Issue: Rate Limiting Errors
Problem: Getting 429 Too Many Requests errors
Solution:
- Implement exponential backoff retry logic
- Reduce request frequency
- Use pagination efficiently (larger
per_pagevalues) - Consider using webhooks instead of polling
Issue: Webhook Not Receiving Events
Problem: Webhook endpoint not receiving events
Solution:
- Verify webhook is active in Admin → API → Webhooks
- Check webhook URL is accessible from internet
- Verify webhook endpoint returns 200 status code
- Check webhook delivery logs in Admin → API → Deliveries
- Ensure webhook has correct event types selected
API Reference Summary
Endpoints
| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
| GET | /api/v1/users |
Bulk user retrieval with pagination and filtering | read:users or admin |
| GET | /api/v1/users/:uid |
Individual user lookup by mango_employee_id | read:users or admin |
| GET | /api/v1/users/by_email/:email |
Individual user lookup by email | read:users or admin |
Required Scopes
| Scope | Description |
|---|---|
read:users |
Read-only access to user data (recommended for HRIS integrations) |
admin |
Full access including user management |
Rate Limits
| Endpoint | Limit |
|---|---|
Bulk retrieval (GET /api/v1/users) |
100 requests/hour per API token |
Individual lookup (GET /api/v1/users/:uid, /by_email/:email) |
300 requests/hour per API token |
Response Status Codes
| Code | Description |
|---|---|
| 200 | Success |
| 401 | Unauthorized - Invalid or expired token |
| 403 | Forbidden - Insufficient scope |
| 404 | Not Found - User not found |
| 429 | Too Many Requests - Rate limit exceeded |
| 500 | Internal Server Error |
Additional Resources
Related Documentation
- API Authentication Guide: Complete authentication system overview
- API Configuration: Setting up API access and tokens
- System Account Impersonation Guide: Using service accounts for advanced integrations
- Custom API: Building custom API endpoints
Developer Tools
- OpenAPI Specification:
/api/v1/docs- Interactive API documentation - API Testing: Use
./api test-hris-userscommand for comprehensive testing - Postman Collection: Available in API documentation
Support
- API Documentation: Available at
/admin/api/documentation - API Analytics: Monitor usage at
/admin/api/analytics - Webhook Logs: View delivery logs at
/admin/api/webhook_deliveries - Audit Logs: Review API access at
/admin/api/audit_logs
Quick Reference
Complete Flow Checklist
- âś… Create API token with
read:usersscope - âś… Store token securely (environment variables)
- âś… Implement bulk user retrieval with pagination
- âś… Use
mango_employee_id(UID) as primary identifier - âś… Implement incremental sync with
updated_afterparameter - âś… Set up webhooks for real-time updates
- âś… Handle errors gracefully (404, 401, 403, 429)
- âś… Implement rate limiting retry logic
- âś… Monitor API usage and audit logs
- âś… Rotate tokens periodically
Code Snippet Template
# 1. Initialize client
client = MangoAppsHRISClient(base_url, api_token)
# 2. Get all users (with pagination)
all_users = client.get_all_users(active_only=True)
# 3. Get user by UID
user = client.get_user_by_uid('E1000001')
# 4. Incremental sync
since = datetime.utcnow() - timedelta(days=1)
updated_users = client.get_users_updated_since(since)
# 5. Use UID as primary identifier in your HRIS system
for user in all_users:
sync_to_hris(user['uid'], user)
Key Identifiers
- Primary UID:
mango_employee_id(format: E1234567) - Use this as the definitive identifier - Fallback ID:
id(integer) - Internal MangoApps ID - Alternative:
external_employee_id- If your system provides its own ID - Lookup:
email- For email-based lookups
This guide covers using the HRIS Users API for external system integrations. For general API authentication, see the API Authentication Guide. For advanced integrations with impersonation, see the System Account Impersonation Guide. Last updated: November 2025.