Skip to main content

List All Users

Overview

Retrieve a paginated list of all Users (API credentials) across your Applications. Use to audit active keys, track environments, and manage access.

Resource Access

  • User Permissions: Admin users only
  • Endpoint: GET /users

Arguments

ParameterTypeRequiredDescription
limitintegerNoNumber of results per page (default: 20, max: 100)
after_cursorstringNoCursor for next page
before_cursorstringNoCursor for previous page

Example Request

curl -X GET \
'https://api.ahrvo.network/payments/na/users?limit=50' \
-u username:password

Example Response

{
"_embedded": {
"users": [
{
"id": "USuser456",
"created_at": "2023-12-10T20:00:00Z",
"updated_at": "2023-12-10T20:00:00Z",
"enabled": true,
"role": "ROLE_MERCHANT",
"tags": {
"environment": "production",
"purpose": "web_checkout",
"created_by": "admin@example.com"
},
"_links": {
"self": {
"href": "https://api.ahrvo.network/payments/na/users/USuser456"
},
"application": {
"href": "https://api.ahrvo.network/payments/na/applications/APapplication123"
}
}
},
{
"id": "USuser457",
"created_at": "2023-12-09T15:30:00Z",
"updated_at": "2023-12-09T15:30:00Z",
"enabled": false,
"role": "ROLE_MERCHANT",
"tags": {
"environment": "production",
"purpose": "web_checkout",
"rotation_date": "2023-12-10",
"replaced_by": "USuser456"
},
"_links": {
"self": {
"href": "https://api.ahrvo.network/payments/na/users/USuser457"
},
"application": {
"href": "https://api.ahrvo.network/payments/na/applications/APapplication123"
}
}
},
{
"id": "USuser458",
"created_at": "2023-12-08T10:00:00Z",
"updated_at": "2023-12-08T10:00:00Z",
"enabled": true,
"role": "ROLE_MERCHANT",
"tags": {
"environment": "development",
"purpose": "local_testing",
"developer": "john@example.com"
},
"_links": {
"self": {
"href": "https://api.ahrvo.network/payments/na/users/USuser458"
},
"application": {
"href": "https://api.ahrvo.network/payments/na/applications/APapplication123"
}
}
}
]
},
"_links": {
"self": {
"href": "https://api.ahrvo.network/payments/na/users?limit=50"
},
"next": {
"href": "https://api.ahrvo.network/payments/na/users?limit=50&after_cursor=dXNlcjQ1OA"
}
},
"page": {
"limit": 50,
"offset": 0,
"count": 3
}
}

Additional Information

  • No Password: Passwords never returned
    • password field only in POST response (creation)
    • Cannot retrieve password later
    • Security feature
    • If lost, create new User
  • Pagination: Cursor-based
    • limit: Results per page (default: 20, max: 100)
    • after_cursor: Get next page
    • before_cursor: Get previous page
    • Follow _links.next for next page
  • Enabled Status: Filter manually
    • No query parameter to filter by enabled
    • Filter in your application
    • true: User can authenticate
    • false: User disabled (cannot authenticate)
  • Role: Permission level
    • ROLE_MERCHANT: Standard merchant access
    • ROLE_PARTNER: Platform/partner access
    • Inherited from Application
    • Cannot filter by role in API
  • Tags: Custom metadata
    • Use to organize keys
    • Filter manually by tags
    • Track environment, purpose, creator
    • No built-in tag filtering
  • Application Link: Parent application
    • _links.application shows which Application
    • Users belong to specific Application
    • Multiple Applications = multiple User lists
    • Follow link for Application details
  • Created At: Creation timestamp
    • ISO 8601 format
    • UTC timezone
    • Use to find old keys
    • Sort by age
  • Updated At: Last modification
    • Changes when tags updated
    • Changes when enabled/disabled
    • Use to track recent changes
  • Sorting: By creation date
    • Newest first (default)
    • Cannot change sort order
    • Paginate for all results

Use Cases

Security Audit

// List all Users and check status
const response = await listUsers({ limit: 100 });
const users = response._embedded.users;

// Find enabled Users
const activeUsers = users.filter(u => u.enabled);
console.log(`Active API keys: ${activeUsers.length}`);

// Find old Users (> 90 days)
const ninetyDaysAgo = new Date();
ninetyDaysAgo.setDate(ninetyDaysAgo.getDate() - 90);

const oldUsers = users.filter(u => {
return new Date(u.created_at) < ninetyDaysAgo && u.enabled;
});

console.log(`Keys older than 90 days: ${oldUsers.length}`);
oldUsers.forEach(u => {
console.log(`- ${u.id}: Created ${u.created_at}`);
console.log(` Tags: ${JSON.stringify(u.tags)}`);
});

Environment Inventory

# List all Users and group by environment
curl -X GET \
'https://api.ahrvo.network/payments/na/users?limit=100' \
-u username:password | \
jq '.._embedded.users | group_by(.tags.environment)'

# Output:
# Production: 5 keys
# Staging: 3 keys
# Development: 7 keys

Find Disabled Keys

// List all Users and find disabled ones
const response = await listUsers({ limit: 100 });
const users = response._embedded.users;

const disabledUsers = users.filter(u => !u.enabled);

console.log('Disabled Users (rotated/revoked):');
disabledUsers.forEach(u => {
console.log(`- ${u.id}`);
console.log(` Disabled: ${u.updated_at}`);
console.log(` Reason: ${u.tags.disabled_reason || 'Not specified'}`);
console.log(` Replaced by: ${u.tags.replaced_by || 'None'}`);
});

Key Rotation Tracking

// Find Users due for rotation
const response = await listUsers({ limit: 100 });
const users = response._embedded.users;

const rotationThreshold = 90; // days
const now = new Date();

const dueForRotation = users.filter(u => {
if (!u.enabled) return false;

const created = new Date(u.created_at);
const ageInDays = (now - created) / (1000 * 60 * 60 * 24);

return ageInDays >= rotationThreshold;
});

console.log('Keys due for rotation:');
dueForRotation.forEach(u => {
const created = new Date(u.created_at);
const ageInDays = Math.floor((now - created) / (1000 * 60 * 60 * 24));

console.log(`- ${u.id}: ${ageInDays} days old`);
console.log(` Environment: ${u.tags.environment}`);
console.log(` Purpose: ${u.tags.purpose}`);
});

Compliance Report

// Generate compliance report for all API keys
async function generateKeyAuditReport() {
const allUsers = [];
let cursor = null;

// Paginate through all Users
do {
const url = cursor
? `/users?after_cursor=${cursor}`
: `/users?limit=100`;

const response = await fetch(url);
const data = await response.json();

allUsers.push(...data._embedded.users);
cursor = data._links.next
? extractCursor(data._links.next.href)
: null;
} while (cursor);

// Analyze
const report = {
total: allUsers.length,
enabled: allUsers.filter(u => u.enabled).length,
disabled: allUsers.filter(u => !u.enabled).length,
byEnvironment: {},
byRole: {},
oldKeys: [],
untagged: []
};

allUsers.forEach(user => {
// Count by environment
const env = user.tags?.environment || 'untagged';
report.byEnvironment[env] = (report.byEnvironment[env] || 0) + 1;

// Count by role
report.byRole[user.role] = (report.byRole[user.role] || 0) + 1;

// Find old keys
const ageInDays = (new Date() - new Date(user.created_at)) / (1000 * 60 * 60 * 24);
if (ageInDays > 90 && user.enabled) {
report.oldKeys.push({
id: user.id,
age: Math.floor(ageInDays),
environment: user.tags?.environment
});
}

// Find untagged keys
if (!user.tags || Object.keys(user.tags).length === 0) {
report.untagged.push(user.id);
}
});

return report;
}

Best Practices

  • Regular Audits: Review Users periodically
    • Monthly or quarterly
    • Check for old keys
    • Verify all keys are tagged
    • Disable unused keys
    • Document active keys
  • Tag Consistently: Always tag Users
    • environment: production, staging, development
    • purpose: web_app, admin_panel, reporting
    • created_by: Who created
    • team: Which team owns
    • Makes auditing easier
  • Track Disabled Keys: Document why disabled
    • Add disabled_reason tag
    • Add disabled_date tag
    • Add replaced_by tag if rotated
    • Helps future audits
  • Pagination: Handle large lists
    • Use cursor pagination
    • Don't assume all Users fit in one page
    • Process page by page
    • Cache results if needed
  • Filter Client-Side: No server filters
    • List all Users
    • Filter by tags in your code
    • Filter by enabled status
    • Filter by creation date
  • Monitor Creation: Track who creates Users
    • Log User creation events
    • Alert on unusual activity
    • Require approval for production keys
    • Audit trail

Common Workflows

Monthly Security Audit

  1. List all Users
  2. Filter for enabled Users
  3. Check age of each User
  4. Identify Users > 90 days old
  5. Plan rotation for old keys
  6. Check for untagged Users
  7. Verify all production keys are documented
  8. Generate audit report

Find Keys to Rotate

async function findKeysToRotate() {
const response = await listUsers({ limit: 100 });
const users = response._embedded.users;

const productionKeys = users.filter(u =>
u.enabled &&
u.tags?.environment === 'production'
);

const rotationAge = 90; // days
const toRotate = productionKeys.filter(u => {
const age = (new Date() - new Date(u.created_at)) / (1000 * 60 * 60 * 24);
return age >= rotationAge;
});

return toRotate.map(u => ({
id: u.id,
age: Math.floor((new Date() - new Date(u.created_at)) / (1000 * 60 * 60 * 24)),
purpose: u.tags?.purpose,
created_at: u.created_at
}));
}

Cleanup Disabled Keys

// Find disabled keys older than 30 days (safe to delete)
async function findOldDisabledKeys() {
const response = await listUsers({ limit: 100 });
const users = response._embedded.users;

const thirtyDaysAgo = new Date();
thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);

const oldDisabled = users.filter(u => {
return !u.enabled &&
new Date(u.updated_at) < thirtyDaysAgo;
});

console.log(`Found ${oldDisabled.length} disabled keys older than 30 days`);

// Review before deletion
oldDisabled.forEach(u => {
console.log(`${u.id}: Disabled ${u.updated_at}`);
});

return oldDisabled;
}

Export for Documentation

// Export all active keys for documentation
async function exportActiveKeys() {
const response = await listUsers({ limit: 100 });
const users = response._embedded.users;

const activeKeys = users
.filter(u => u.enabled)
.map(u => ({
id: u.id,
environment: u.tags?.environment,
purpose: u.tags?.purpose,
created: u.created_at,
team: u.tags?.team || u.tags?.created_by
}));

// Export to CSV
const csv = [
'ID,Environment,Purpose,Created,Team',
...activeKeys.map(k =>
`${k.id},${k.environment},${k.purpose},${k.created},${k.team}`
)
].join('\n');

return csv;
}

Security Considerations

  • Access Control: Limit who can list Users
    • Only admin/security team
    • Lists all API credentials
    • Sensitive information
    • Audit access to this endpoint
  • Disabled Keys: Don't delete immediately
    • Disable first
    • Wait 30+ days
    • Verify no longer used
    • Then consider deletion
    • Allows rollback if needed
  • Old Keys: Rotate regularly
    • 90 days maximum recommended
    • 30-60 days for high security
    • Automated rotation ideal
    • Track rotation schedule
  • Untagged Keys: Investigate
    • May be forgotten/orphaned
    • Hard to track ownership
    • Potential security risk
    • Tag or disable
  • POST /applications/{id}/users: Create new User
  • GET /users/{id}: Fetch specific User details
  • PUT /users/{id}: Update User (disable, update tags)
  • GET /applications/{id}: View parent Application