> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://partner.ninjatrader.com/eval/overview/conformance-testing/stage-3-user-management/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).