Fetch a User
Overview
Retrieve detailed information about a specific User (API credential) by its ID. View status, role, tags, and parent Application.
Resource Access
- User Permissions: Admin users only
- Endpoint:
GET /users/\{user_id}
Arguments
| Parameter | Type | Required | Description |
|---|---|---|---|
| user_id | string | Yes | Unique User ID (in URL path) |
Example Request
curl -X GET \
'https://api.ahrvo.network/payments/na/users/USuser456' \
-u username:password
Example Response (Enabled User)
{
"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",
"server": "web-01"
},
"_links": {
"self": {
"href": "https://api.ahrvo.network/payments/na/users/USuser456"
},
"application": {
"href": "https://api.ahrvo.network/payments/na/applications/APapplication123"
}
}
}
Example Response (Disabled User)
{
"id": "USuser457",
"created_at": "2023-12-09T15:30:00Z",
"updated_at": "2023-12-10T20:00:00Z",
"enabled": false,
"role": "ROLE_MERCHANT",
"tags": {
"environment": "production",
"purpose": "web_checkout",
"rotation_date": "2023-12-10",
"replaced_by": "USuser456",
"disabled_reason": "key_rotation",
"disabled_by": "devops@example.com"
},
"_links": {
"self": {
"href": "https://api.ahrvo.network/payments/na/users/USuser457"
},
"application": {
"href": "https://api.ahrvo.network/payments/na/applications/APapplication123"
}
}
}
Additional Information
- User ID: API username
- Starts with "US"
- Used for Basic Authentication username
- Example:
USuser456 - Immutable (cannot change)
- No Password: Never returned
passwordfield only shown on creation- Cannot retrieve password later
- Security feature
- If lost, must create new User
- No password reset endpoint
- Enabled: Active status
true: User can authenticate- API requests succeed
- Credentials are valid
- Active key
false: User cannot authenticate- API requests fail with 401
- Credentials rejected
- Disabled/revoked key
- Change via PUT /users/{id}
- Role: Permission level
- ROLE_MERCHANT: Standard merchant access
- Create transfers
- Manage payment instruments
- View own data
- Most common role
- ROLE_PARTNER: Platform/partner access
- Create merchants
- Create applications
- Platform-level operations
- Higher privileges
- Inherited from Application
- Cannot change role
- ROLE_MERCHANT: Standard merchant access
- Created At: When User was created
- ISO 8601 timestamp
- UTC timezone
- Never changes
- Use to calculate age
- Track rotation schedule
- Updated At: Last modification
- Changes when enabled/disabled
- Changes when tags updated
- ISO 8601 timestamp
- Use to track recent changes
- Tags: Custom metadata
- Key-value pairs
- Track purpose, environment, owner
- Searchable (manually)
- Mutable via PUT
- Empty object if no tags
- Application Link: Parent application
_links.applicationshows which Application- Users belong to one Application
- Follow link for Application details
- Cannot move User to different Application
- Use Case: Verify credentials
- Check if User is enabled
- Verify environment tag
- Confirm ownership
- Debug authentication issues
Use Cases
Verify User Status
# Check if API key is active
curl -X GET \
'https://api.ahrvo.network/payments/na/users/USuser456' \
-u username:password
# Check enabled field
# true = active, false = disabled
Debug Authentication Issues
// Customer reports 401 errors
async function debugAuthIssue(userId) {
const user = await fetchUser(userId);
if (!user.enabled) {
console.error('User is disabled');
console.log('Disabled on:', user.updated_at);
console.log('Reason:', user.tags.disabled_reason);
console.log('Replaced by:', user.tags.replaced_by);
return 'User disabled - credentials need rotation';
}
console.log('User is enabled and should work');
console.log('Environment:', user.tags.environment);
console.log('Purpose:', user.tags.purpose);
return 'User active - check other issues';
}
Verify Environment
// Ensure using correct environment credentials
async function verifyEnvironment(userId, expectedEnv) {
const user = await fetchUser(userId);
const actualEnv = user.tags.environment;
if (actualEnv !== expectedEnv) {
console.warn(`Warning: Using ${actualEnv} credentials, expected ${expectedEnv}`);
return false;
}
console.log(`✓ Correct environment: ${actualEnv}`);
return true;
}
// Usage
await verifyEnvironment('USuser456', 'production');
Track Key Age
// Check if key needs rotation
async function checkKeyAge(userId) {
const user = await fetchUser(userId);
const created = new Date(user.created_at);
const now = new Date();
const ageInDays = Math.floor((now - created) / (1000 * 60 * 60 * 24));
console.log(`User ${userId}:`);
console.log(` Created: ${user.created_at}`);
console.log(` Age: ${ageInDays} days`);
console.log(` Environment: ${user.tags.environment}`);
if (ageInDays > 90) {
console.warn(` ⚠ Key is ${ageInDays} days old - rotation recommended`);
return { needsRotation: true, age: ageInDays };
}
console.log(` ✓ Key age is acceptable`);
return { needsRotation: false, age: ageInDays };
}
Audit User Details
// Get full User details for audit
async function auditUser(userId) {
const user = await fetchUser(userId);
return {
id: user.id,
status: user.enabled ? 'Active' : 'Disabled',
role: user.role,
created: user.created_at,
updated: user.updated_at,
ageInDays: Math.floor(
(new Date() - new Date(user.created_at)) / (1000 * 60 * 60 * 24)
),
environment: user.tags?.environment || 'untagged',
purpose: user.tags?.purpose || 'untagged',
owner: user.tags?.created_by || 'unknown',
applicationId: user._links.application.href.split('/').pop()
};
}
Find Replacement Key
// User is disabled, find replacement
async function findReplacement(disabledUserId) {
const user = await fetchUser(disabledUserId);
if (user.enabled) {
console.log('User is still enabled');
return null;
}
const replacementId = user.tags.replaced_by;
if (!replacementId) {
console.warn('No replacement key specified in tags');
return null;
}
const replacement = await fetchUser(replacementId);
console.log('Disabled key:', disabledUserId);
console.log('Replacement key:', replacementId);
console.log('Replacement status:', replacement.enabled ? 'Active' : 'Disabled');
return replacement;
}
Best Practices
- Check Enabled Status: Before using credentials
- Verify
enabled: true - Disabled users cannot authenticate
- Update credentials if disabled
- Check tags for replacement
- Verify
- Monitor Age: Track key rotation
- Calculate days since creation
- Rotate keys > 90 days
- Set reminders for rotation
- Automate rotation checks
- Verify Tags: Ensure proper tagging
- Check environment tag
- Verify purpose tag
- Confirm owner/creator
- Add missing tags
- Debug Auth: First step for 401 errors
- Fetch User to check status
- Verify enabled status
- Check for rotation info
- Look for replacement key
- Documentation: Use for reference
- Document which User IDs are used
- Track what each User is for
- Link to deployment configs
- Update when rotated
Common Workflows
Authentication Debugging Flow
- User reports 401 Unauthorized errors
- Get User ID they're using
- Fetch User details
- Check
enabledfield - If
false: Check tags for replacement - If
true: Check other auth issues (wrong password, etc.) - Update application with correct credentials
Key Rotation Verification
async function verifyRotation(oldUserId, newUserId) {
const oldUser = await fetchUser(oldUserId);
const newUser = await fetchUser(newUserId);
// Verify old key is disabled
if (oldUser.enabled) {
console.warn('Old key is still enabled!');
return false;
}
// Verify new key is enabled
if (!newUser.enabled) {
console.error('New key is disabled!');
return false;
}
// Verify tags link them
if (oldUser.tags.replaced_by !== newUserId) {
console.warn('Old key does not reference new key in tags');
}
console.log('✓ Rotation verified successfully');
return true;
}
Environment Validation
// Before deploying to production
async function validateProductionKey(userId) {
const user = await fetchUser(userId);
const checks = {
enabled: user.enabled,
environment: user.tags.environment === 'production',
role: user.role === 'ROLE_MERCHANT',
tagged: Object.keys(user.tags).length > 0
};
const allPassed = Object.values(checks).every(v => v);
if (!allPassed) {
console.error('Production key validation failed:');
console.log(checks);
throw new Error('Invalid production credentials');
}
console.log('✓ Production credentials validated');
return true;
}
Compliance Check
// Verify User meets compliance requirements
async function complianceCheck(userId) {
const user = await fetchUser(userId);
const issues = [];
// Check age
const ageInDays = (new Date() - new Date(user.created_at)) / (1000 * 60 * 60 * 24);
if (ageInDays > 90) {
issues.push(`Key age (${Math.floor(ageInDays)} days) exceeds 90-day rotation policy`);
}
// Check tags
if (!user.tags.environment) {
issues.push('Missing environment tag');
}
if (!user.tags.created_by) {
issues.push('Missing created_by tag (ownership unclear)');
}
if (!user.tags.purpose) {
issues.push('Missing purpose tag');
}
// Check disabled keys
if (!user.enabled) {
const disabledDate = new Date(user.updated_at);
const daysSinceDisabled = (new Date() - disabledDate) / (1000 * 60 * 60 * 24);
if (daysSinceDisabled > 30) {
issues.push(`Disabled key older than 30 days - consider deletion`);
}
}
return {
compliant: issues.length === 0,
issues
};
}
Security Considerations
- Password Never Visible: By design
- Cannot retrieve password after creation
- Must create new User if lost
- Prevents credential leakage
- Store password securely on creation
- Verify Before Use: Always check enabled
- Don't assume credentials work
- Check status before deployment
- Verify environment tag matches
- Confirm key is active
- Audit Trail: Track changes
updated_atshows last change- Tags can track who disabled and why
- Log when fetching User details
- Monitor for suspicious access
- Limited Access: Restrict who can view
- Only admin/devops team
- Shows credential status
- Could aid attacker
- Audit access to this endpoint
Related Endpoints
- POST /applications/{id}/users: Create new User
- GET /users: List all Users
- PUT /users/{id}: Update User (disable, update tags)
- GET /applications/{id}: View parent Application