Skip to main content

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

ParameterTypeRequiredDescription
user_idstringYesUnique User ID (in URL path)
enabledbooleanNoEnable (true) or disable (false) the User
tagsobjectNoCustom 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_at reflects last modification
    • Original created_at unchanged
    • 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 disabled
    • disabled_date: When disabled
    • disabled_by: Who disabled
    • replaced_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
  • POST /applications/{id}/users: Create new User
  • GET /users: List all Users
  • GET /users/{id}: Fetch User details
  • GET /applications/{id}: View parent Application