> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://partner.ninjatrader.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://partner.ninjatrader.com/_mcp/server.

# Stage 3: User Management

User management is critical for B2B partners managing evaluation traders. This stage validates your integration's ability to create, manage, and terminate users within the evaluation system.

## Overview

The user management stage ensures your application can:

* Create evaluation users with proper configuration
* Manage user entitlements and permissions
* Terminate users and clean up associated resources
* Handle user lifecycle events and state changes

## Required Tests

### 1. User Creation

**Endpoint:** `POST /user/createevaluationusers`

### Response (200)

```json
{
  "results": [
    {
      "errorText": "string",
      "userId": 1
    }
  ],
  "errorText": "string"
}
```

**Purpose:** Create new evaluation users for the trading platform.

**Test Steps:**

1. Create a single evaluation user with valid parameters
2. Optionally, create multiple users in batch (up to 100)
3. Store the user ID in your system for future reference

**Example Request:**

```javascript
// Single user creation
const requestBody = {
    users: [{
        name: "testuser1",
        email: "testuser1@example.com",
        password: "SecurePassword123!",
        firstName: "Test",
        lastName: "User",
    }]
};

const response = await fetch('https://live.tradovateapi.com/v1/user/createevaluationusers', {
    method: 'POST',
    headers: {
        'Authorization': `Bearer ${accessToken}`,
        'Content-Type': 'application/json',
        'Accept': 'application/json'
    },
    body: JSON.stringify(requestBody)
});

const data = await response.json();
```

**Batch User Creation:**

```javascript
// Batch user creation (up to 100 users)
const requestBody = {
    users: Array.from({ length: 10 }, (_, i) => ({
        name: `testuser${i + 1}`,
        email: `testuser${i + 1}@example.com`,
        password: `SecurePassword${i + 1}!`,
        firstName: "Test",
        lastName: `User${i + 1}`,
    }))
};

const response = await fetch('https://live.tradovateapi.com/v1/user/createevaluationusers', {
    method: 'POST',
    headers: {
        'Authorization': `Bearer ${accessToken}`,
        'Content-Type': 'application/json',
        'Accept': 'application/json'
    },
    body: JSON.stringify(requestBody)
});
```

**Expected Response:**

```json
{
    "results": [
        {
            "id": 12345,
            "name": "testuser1",
            "email": "testuser1@example.com",
            "firstName": "Test",
            "lastName": "User",
            "status": "Active",
            "createdAt": "2024-01-01T12:00:00.000Z"
        }
    ],
    "errorText": ""
}
```

**Validation Criteria:**

* ✅ Users are created successfully with valid data
* ✅ Batch creation works for multiple users
* ✅ User data is stored correctly
* ✅ Duplicate usernames/emails are rejected
* ✅ Invalid data returns appropriate errors

### 2. Contact Information Management (Optional)

**Endpoint:** `POST /contactinfo/updatecontactinfo`

**Purpose:** Update user contact information after user creation, this is optional but recommended.

**Test Steps:**

1. Update user contact information with valid data
2. Verify contact information is updated correctly
3. Test error handling for invalid contact data
4. Verify contact information validation rules

**Example Request:**

```javascript
const contactUpdate = {
    userId: 12345,
    phone: "+1234567890",
    firstName: "John",
    lastName: "Doe",
    streetAddress1: "123 Main St",
    city: "New York",
    state: "NY", // only required when country is "US"
    postCode: "12345",
    country: "US",
};

const response = await fetch('https://live.tradovateapi.com/v1/contactinfo/updatecontactinfo', {
    method: 'POST',
    headers: {
        'Authorization': `Bearer ${accessToken}`,
        'Content-Type': 'application/json',
        'Accept': 'application/json'
    },
    body: JSON.stringify(contactUpdate)
});

const data = await response.json();
```

**Expected Response:**

```json
{
    "success": true,
    "message": "Contact information updated successfully",
    "userId": 12345,
    "updatedAt": "2024-01-01T12:00:00.000Z"
}
```

**Validation Criteria:**

* ✅ Contact information is updated successfully
* ✅ Phone number validation works correctly
* ✅ Address validation works correctly
* ✅ Invalid data returns appropriate errors
* ✅ User ID validation works correctly

### 3. Entitlement Management

**Endpoints:**

* `POST /userPlugin/addentitlementsubscription`
* `POST /user/canceleverything`

**Purpose:** Manage user Sim+ entitlement.

**Test Steps:**

1. Wait for user to be verified (they must sign the Market Data Agreement)
2. Add Sim+ entitlement subscriptions to verified users
3. Cancel all subscriptions and permissions for users at the end of their lifecycle

**Add Entitlement Subscription:**

```javascript
async function addEntitlementWithAgreementCheck(userId, accountId) {
    // Step 1: Check for agreement signatures using adminAlertSignal/deps, use masterid=70 in staging
    const alertResponse = await fetch(`https://live.tradovateapi.com/v1/adminAlertSignal/deps?masterid=68`, {
        method: 'GET',
        headers: {
            'Authorization': `Bearer ${accessToken}`,
            'Accept': 'application/json'
        }
    });
    
    const alerts = await alertResponse.json();
    
    // Step 2: Find alerts for the specific user that don't have 'complete' field
    const pendingAgreements = alerts.filter(alert => !alert.complete);
    
    if (pendingAgreements.length === 0) {
        console.log('No pending agreements found for user:', userId);
        return { success: false, message: 'No pending agreements found' };
    }
    
    // Step 3: Add the entitlement subscription
    const addEntitlement = {
        entitlementId: 12345, // Required: ID of the entitlement to add
        userId: userId,
        accountId: accountId, // This should be the ID of your Live _DATA account.
    };

    const entitlementResponse = await fetch('https://live.tradovateapi.com/v1/userPlugin/addentitlementsubscription', {
        method: 'POST',
        headers: {
            'Authorization': `Bearer ${accessToken}`,
            'Content-Type': 'application/json',
            'Accept': 'application/json'
        },
        body: JSON.stringify(addEntitlement)
    });

    const entitlementData = await entitlementResponse.json();
    
    // Step 4: Complete the alert signal after successful entitlement addition
    if (entitlementData.errorCode === 'Success') {
        for (const alert of pendingAgreements) {
            await fetch('https://live.tradovateapi.com/v1/adminAlertSignal/completealertsignal', {
                method: 'POST',
                headers: {
                    'Authorization': `Bearer ${accessToken}`,
                    'Content-Type': 'application/json',
                    'Accept': 'application/json'
                },
                body: JSON.stringify({
                    alertId: alert.id,
                    userId: userId
                })
            });
        }
    }
    
    return entitlementData;
}

// Usage example
const result = await addEntitlementWithAgreementCheck(67890, 11111);
console.log('Entitlement addition result:', result);
```

**Cancel Everything (All Subscriptions and Permissions):**

```javascript
const cancelEverything = {
    userIds: [12345, 67890], // Required: Array of user IDs
    tradovateSubscriptions: true, // Optional: Cancel Tradovate subscriptions
    tradingPermissions: true, // Optional: Revoke trading permissions
    userPlugins: true, // Optional: Cancel user plugin subscriptions
    marketDataSubscriptions: true // Optional: Cancel market data subscriptions
};

const response = await fetch('https://live.tradovateapi.com/v1/user/canceleverything', {
    method: 'POST',
    headers: {
        'Authorization': `Bearer ${accessToken}`,
        'Content-Type': 'application/json',
        'Accept': 'application/json'
    },
    body: JSON.stringify(cancelEverything)
});

const data = await response.json();
```

**Expected Response for Add Entitlement:**

```json
{
    "errorText": "",
    "errorCode": "Success",
    "entitlementSubscription": {
        "id": 99999,
        "userId": 67890,
        "accountId": 11111,
        "entitlementId": 12345,
        "status": "Active",
        "createdAt": "2024-01-01T12:00:00.000Z"
    }
}
```

**Expected Response for Cancel Everything:**

```json
{
    "success": true,
    "cancelledUsers": [12345, 67890],
    "tradovateSubscriptionsCancelled": 2,
    "tradingPermissionsRevoked": 2,
    "userPluginsCancelled": 1,
    "marketDataSubscriptionsCancelled": 2
}
```

**Validation Criteria:**

* ✅ Agreement signatures are checked before adding entitlements
* ✅ Entitlements are only added for users with pending agreements (no 'complete' field)
* ✅ Alert signals are completed after successful entitlement addition
* ✅ Entitlement subscriptions are added successfully
* ✅ Required entitlementId parameter is validated
* ✅ Cancel everything works for multiple users
* ✅ All subscription types are cancelled when requested
* ✅ Invalid entitlement operations are rejected
* ✅ Entitlement changes are reflected immediately
* ✅ Billing and payment handling works correctly

## User Lifecycle Management

### Required Fields for User Creation

* `name`: Unique username (3-64 characters)
* `email`: Valid email address (max 64 characters)
* `password`: Secure password (8-64 characters)
* `firstName`: First name (max 60 characters combined with `lastName`)
* `lastName`: Last name (max 60 characters combined with `firstName`)

### Optional Fields

* `tradovateSubscriptionPlanId`: Organization-specific subscription plan ID (integer > 0)
* `entitlementIds`: Array of entitlement IDs to pre-assign (array of integers)
* **NOTE**: Do *not* pass the Sim+ entitlement here, users are not valid until they sign the Market Data Agreement

## Testing Checklist

* [ ] Single user creation works correctly
* [ ] Batch user creation works for multiple users
* [ ] User data validation works properly
* [ ] Duplicate user prevention works
* [ ] Subscription management functions correctly
* [ ] User termination works properly
* [ ] Resource cleanup is complete
* [ ] Error handling is robust
* [ ] Performance requirements are met
* [ ] Security requirements are satisfied

## Next Steps

After completing Stage 3 user management tests, proceed to [Stage 4: Account Management](/overview/conformance-testing/stage-4-account-management).