Update a User
Overview
Update a User's enabled status or metadata tags. Use this to disable/enable API credentials or add tracking information.
Resource Access
- User Permissions: Admin users only
- Endpoint:
PUT /users/\{user_id}
Arguments
| Parameter | Type | Required | Description |
|---|---|---|---|
| user_id | string | Yes | Unique User ID (in URL path) |
| enabled | boolean | No | Enable (true) or disable (false) the User |
| tags | object | No | Custom key-value metadata |
Example Request (Disable User)
curl -X PUT \
'https://api.ahrvo.network/payments/na/users/USuser456' \
-u username:password \
-H 'Content-Type: application/json' \
-d '{
"enabled": false,
"tags": {
"environment": "production",
"purpose": "web_checkout",
"disabled_reason": "key_rotation",
"disabled_date": "2023-12-10",
"disabled_by": "devops@example.com",
"replaced_by": "USuser789"
}
}'
Example Request (Update Tags Only)
curl -X PUT \
'https://api.ahrvo.network/payments/na/users/USuser456' \
-u username:password \
-H 'Content-Type: application/json' \
-d '{
"tags": {
"environment": "production",
"purpose": "web_checkout",
"created_by": "admin@example.com",
"server": "web-01",
"last_rotated": "2023-12-10",
"rotation_schedule": "quarterly"
}
}'
Example Request (Re-enable User)
curl -X PUT \
'https://api.ahrvo.network/payments/na/users/USuser456' \
-u username:password \
-H 'Content-Type: application/json' \
-d '{
"enabled": true,
"tags": {
"environment": "production",
"purpose": "web_checkout",
"re_enabled_date": "2023-12-11",
"re_enabled_by": "support@example.com",
"reason": "emergency_rollback"
}
}'
Example Response
{
"id": "USuser456",
"created_at": "2023-12-10T20:00:00Z",
"updated_at": "2023-12-10T21:30:00Z",
"enabled": false,
"role": "ROLE_MERCHANT",
"tags": {
"environment": "production",
"purpose": "web_checkout",
"disabled_reason": "key_rotation",
"disabled_date": "2023-12-10",
"disabled_by": "devops@example.com",
"replaced_by": "USuser789"
},
"_links": {
"self": {
"href": "https://api.ahrvo.network/payments/na/users/USuser456"
},
"application": {
"href": "https://api.ahrvo.network/payments/na/applications/APapplication123"
}
}
}
Additional Information
- Enabled Field: Enable or disable User
true: User can authenticate- API requests succeed
- Credentials are valid
- Key is active
false: User cannot authenticate- API requests fail with 401 Unauthorized
- Credentials rejected immediately
- Key is revoked/disabled
- Use to disable compromised keys
- Use after key rotation
- Use to temporarily revoke access
- Tags Replacement: Complete replacement
- New tags object REPLACES old tags
- Existing tags not in request are DELETED
- Always send complete tags object
- Example: Old tags
{a: 1, b: 2}, Update with{c: 3}→ Result:{c: 3} - Include existing tags + new tags in request
- Updated At: Timestamp changes
updated_atreflects last modification- Original
created_atunchanged - Use to track when User was disabled/updated
- Cannot Change:
- User ID (immutable)
- Password (no password reset - create new User)
- Role (inherited from Application)
- Application (User cannot move)
- Created date
- Disable vs Delete: Best practice
- Disable instead of delete
- Keeps audit trail
- Allows re-enable if needed
- Tag with disable reason
- Delete only after retention period (e.g., 30+ days)
- Idempotency: Safe to retry
- Same values = same result
- No side effects
- Can update multiple times
- Immediate Effect: Instant revocation
- Disabled User fails auth immediately
- No grace period
- In-flight requests may complete
- New requests fail
- Use Cases:
- Key rotation (disable old, enable new)
- Revoke compromised credentials
- Temporary access suspension
- Add tracking metadata
- Document key purpose/ownership
Use Cases
Key Rotation (Disable Old Key)
# After deploying new credentials, disable old ones
curl -X PUT \
'https://api.ahrvo.network/payments/na/users/USolduser123' \
-u username:password \
-H 'Content-Type: application/json' \
-d '{
"enabled": false,
"tags": {
"environment": "production",
"purpose": "web_checkout",
"disabled_reason": "key_rotation",
"disabled_date": "2023-12-10",
"disabled_by": "devops@example.com",
"replaced_by": "USnewuser456",
"rotation_cycle": "Q4_2023"
}
}'
Revoke Compromised Key
# Immediately disable compromised credentials
curl -X PUT \
'https://api.ahrvo.network/payments/na/users/UScompromised789' \
-u username:password \
-H 'Content-Type: application/json' \
-d '{
"enabled": false,
"tags": {
"environment": "production",
"purpose": "web_checkout",
"disabled_reason": "security_incident",
"disabled_date": "2023-12-10T15:30:00Z",
"disabled_by": "security@example.com",
"incident_id": "INC-2023-456",
"replaced_by": "USnewuser999"
}
}'
Add Metadata After Creation
# Add tags to existing User
# First, fetch to get existing tags
curl -X GET \
'https://api.ahrvo.network/payments/na/users/USuser456' \
-u username:password
# Then update with existing + new tags
curl -X PUT \
'https://api.ahrvo.network/payments/na/users/USuser456' \
-u username:password \
-H 'Content-Type: application/json' \
-d '{
"tags": {
"environment": "production",
"purpose": "web_checkout",
"created_by": "admin@example.com",
"server": "web-01",
"deployment_date": "2023-12-10",
"team": "engineering"
}
}'
Temporary Suspension
# Temporarily disable during maintenance
curl -X PUT \
'https://api.ahrvo.network/payments/na/users/USuser456' \
-u username:password \
-H 'Content-Type: application/json' \
-d '{
"enabled": false,
"tags": {
"environment": "staging",
"purpose": "testing",
"disabled_reason": "maintenance",
"disabled_date": "2023-12-10",
"disabled_by": "ops@example.com",
"expected_re_enable": "2023-12-11"
}
}'
# Re-enable after maintenance
curl -X PUT \
'https://api.ahrvo.network/payments/na/users/USuser456' \
-u username:password \
-H 'Content-Type: application/json' \
-d '{
"enabled": true,
"tags": {
"environment": "staging",
"purpose": "testing",
"re_enabled_date": "2023-12-11",
"re_enabled_by": "ops@example.com"
}
}'
Emergency Rollback
# Production issues, re-enable old key temporarily
curl -X PUT \
'https://api.ahrvo.network/payments/na/users/USolduser123' \
-u username:password \
-H 'Content-Type: application/json' \
-d '{
"enabled": true,
"tags": {
"environment": "production",
"purpose": "web_checkout",
"re_enabled_date": "2023-12-10T16:00:00Z",
"re_enabled_by": "oncall@example.com",
"reason": "emergency_rollback",
"incident": "Production deployment failed",
"temp_enable": "true"
}
}'
Best Practices
- Include Existing Tags: Always preserve tags
// WRONG: Will delete existing tags
await updateUser(userId, {
tags: { disabled_reason: 'rotation' }
});
// RIGHT: Include existing tags
const user = await fetchUser(userId);
await updateUser(userId, {
tags: {
...user.tags,
disabled_reason: 'rotation',
disabled_date: new Date().toISOString(),
replaced_by: newUserId
}
}); - Tag Disable Reasons: Always document
disabled_reason: Why disableddisabled_date: When disableddisabled_by: Who disabledreplaced_by: New User ID (if rotation)- Helpful for audits and debugging
- Verify Before Disabling: Ensure safe
- Check if User is in production use
- Verify replacement is deployed
- Test replacement first
- Have rollback plan
- Disable during low traffic
- Gradual Rollout: For key rotation
- Deploy new credentials
- Test new credentials
- Monitor for errors
- Wait 24-48 hours
- Then disable old credentials
- Allows easy rollback
- Don't Delete: Disable instead
- Keeps audit trail
- Can re-enable if needed
- No loss of history
- Delete only after 30+ days
- Monitor After Disabling: Watch for issues
- Check error logs
- Monitor auth failures
- Verify services still work
- Be ready to re-enable
- Automation: Script common tasks
- Automated rotation schedules
- Batch disable old keys
- Compliance checks
- Audit trail generation
Common Workflows
Key Rotation Workflow
async function rotateApiKey(oldUserId, applicationId) {
// 1. Create new User
const newUser = await createUser(applicationId, {
tags: {
environment: 'production',
purpose: 'web_checkout',
rotation_date: new Date().toISOString(),
replaces: oldUserId
}
});
console.log('New User created:', newUser.id);
console.log('Password (save this!):', newUser.password);
// 2. Deploy new credentials
await deployCredentials({
username: newUser.id,
password: newUser.password
});
// 3. Wait for deployment
await sleep(60000); // Wait 1 minute
// 4. Verify new credentials work
const testResult = await testApiAccess(newUser.id);
if (!testResult.success) {
console.error('New credentials failed, keeping old ones');
return;
}
// 5. Disable old User
const oldUser = await fetchUser(oldUserId);
await updateUser(oldUserId, {
enabled: false,
tags: {
...oldUser.tags,
disabled_reason: 'key_rotation',
disabled_date: new Date().toISOString(),
replaced_by: newUser.id
}
});
console.log('Old User disabled:', oldUserId);
console.log('Rotation complete!');
}
Bulk Disable Old Keys
async function disableOldKeys(ageInDays = 90) {
const response = await listUsers({ limit: 100 });
const users = response._embedded.users;
const oldUsers = users.filter(u => {
if (!u.enabled) return false; // Already disabled
const age = (new Date() - new Date(u.created_at)) / (1000 * 60 * 60 * 24);
return age > ageInDays;
});
console.log(`Found ${oldUsers.length} keys older than ${ageInDays} days`);
for (const user of oldUsers) {
console.log(`Disabling ${user.id} (${Math.floor((new Date() - new Date(user.created_at)) / (1000 * 60 * 60 * 24))} days old)`);
await updateUser(user.id, {
enabled: false,
tags: {
...user.tags,
disabled_reason: 'age_policy',
disabled_date: new Date().toISOString(),
disabled_by: 'automated_script',
original_age_days: Math.floor((new Date() - new Date(user.created_at)) / (1000 * 60 * 60 * 24))
}
});
}
console.log('Bulk disable complete');
}
Tag Update Helper
// Helper to safely update User tags
async function updateUserTags(userId, newTags) {
// Fetch current User
const user = await fetchUser(userId);
// Merge with existing tags
const updatedTags = {
...user.tags,
...newTags
};
// Update User
await updateUser(userId, {
enabled: user.enabled, // Keep current status
tags: updatedTags
});
return updatedTags;
}
// Usage
await updateUserTags('USuser456', {
last_audit: '2023-12-10',
audit_status: 'passed'
});
Emergency Re-enable
// Quick re-enable for emergency rollback
async function emergencyReEnable(userId, reason) {
const user = await fetchUser(userId);
await updateUser(userId, {
enabled: true,
tags: {
...user.tags,
re_enabled_date: new Date().toISOString(),
re_enabled_by: 'emergency_procedure',
emergency_reason: reason,
previous_disable_date: user.tags.disabled_date
}
});
console.log(`User ${userId} re-enabled`);
console.log(`Reason: ${reason}`);
console.log('Remember to investigate and rotate again!');
}
// Usage
await emergencyReEnable('USolduser123', 'Production deployment failed');
Security Considerations
- Immediate Revocation: Disabling is instant
- Auth fails immediately
- No grace period
- Use for emergency revocation
- Test impact before disabling production keys
- Audit Trail: Track all changes
- Log who disabled and why
- Store in tags
- External audit log recommended
- Compliance requirement
- Compromised Keys: Act fast
- Disable immediately
- Don't wait for rotation schedule
- Create new User
- Deploy ASAP
- Investigate breach
- Re-enabling: Use with caution
- Verify reason is valid
- Temporary only
- Plan proper fix
- Don't re-enable compromised keys
- Monitoring: Watch for misuse
- Alert on User updates
- Track who disables keys
- Monitor unusual patterns
- Audit access to this endpoint
Related Endpoints
- POST /applications/{id}/users: Create new User
- GET /users: List all Users
- GET /users/{id}: Fetch User details
- GET /applications/{id}: View parent Application