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

# Create and Manage Users and Accounts

When you're ready to onboard traders, this guide walks you through creating users, setting up evaluation accounts, and assigning entitlements.

> **Tip**
>
> Use batched creation operations when possible, even for single users. Batched endpoints are more efficient than individual API calls.

---

## Prerequisites

Before you start, gather the following IDs. You'll reuse them for every user and account you create.

### Tradovate Subscription Plan ID

Each organization has a unique Tradovate Subscription Plan. You'll use this ID as the `tradovateSubscriptionPlanId` field when creating users.

To find your organization's Tradovate subscription plan ID:

#### API

From the environment (staging or production) that matches where you'll be creating accounts, call `/tradovateSubscriptionPlan/list` to get all available subscription plans. Use the plan associated with your firm, named `<YOUR FIRM NAME>_MONTHLY`.

### Request

GET [https://demo.tradovateapi.com/v1/tradovateSubscriptionPlan/list](https://demo.tradovateapi.com/v1/tradovateSubscriptionPlan/list)

```curl
curl https://demo.tradovateapi.com/v1/tradovateSubscriptionPlan/list \
     -H "Authorization: Bearer <token>" \
     -H "Content-Type: application/json"
```

```python
import requests

url = "https://demo.tradovateapi.com/v1/tradovateSubscriptionPlan/list"

payload = {}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.get(url, json=payload, headers=headers)

print(response.json())
```

```javascript
const url = 'https://demo.tradovateapi.com/v1/tradovateSubscriptionPlan/list';
const options = {
  method: 'GET',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://demo.tradovateapi.com/v1/tradovateSubscriptionPlan/list"

	payload := strings.NewReader("{}")

	req, _ := http.NewRequest("GET", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://demo.tradovateapi.com/v1/tradovateSubscriptionPlan/list")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{}"

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.get("https://demo.tradovateapi.com/v1/tradovateSubscriptionPlan/list")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{}")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://demo.tradovateapi.com/v1/tradovateSubscriptionPlan/list', [
  'body' => '{}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://demo.tradovateapi.com/v1/tradovateSubscriptionPlan/list");
var request = new RestRequest(Method.GET);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://demo.tradovateapi.com/v1/tradovateSubscriptionPlan/list")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: \{ (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

#### Dashboards

1. From the Admin Dashboards in the environment (staging or production) that matches where you'll be creating accounts, click **Query Builder** on the left pane.

2. Choose `tradovateSubscriptionPlans` from the **Repository** drop-down.

3. Set **Order By** to `id` and **Limit** to 100+.

4. Run the query.
   * [Example query (staging)](https://dashboards.staging.ninjatrader.dev/query-builder?asc=true\&ids=\&limit=1000\&masterIds=\&orderBy=id\&queryType=regular\&recentPeriodSeconds=3600\&repository=tradovateSubscriptionPlans\&selection=id%20name%20title%20price%20startDate%20discontinuedDate%20admin%20category%20trial%20duration%20durationUnits%20multipleAccounts%20replaySessions%20footnote%20replayProducts%20simOnly%20ntcSalesCode%20lifetimeInstallments%20riskCategory%20%7B%20name%20%7D%20organization%20%7B%20name%20%7D\&where=name%20like%20%22%28%3Fium%29.%2A_MONTHLY%22)
   * [Example query (production)](https://dashboards.tradovate.com/query-builder?asc=true\&ids=\&limit=1000\&masterIds=\&orderBy=id\&queryType=regular\&recentPeriodSeconds=3600\&repository=tradovateSubscriptionPlans\&selection=id%20name%20title%20price%20startDate%20discontinuedDate%20admin%20category%20trial%20duration%20durationUnits%20multipleAccounts%20replaySessions%20footnote%20replayProducts%20simOnly%20ntcSalesCode%20lifetimeInstallments%20riskCategory%20%7B%20name%20%7D%20organization%20%7B%20name%20%7D\&where=name%20like%20%22%28%3Fium%29.%2A_MONTHLY%22)

5. Find the plan labeled `<YOUR FIRM NAME>_MONTHLY` and record its ID.

### Template Account ID

Evaluation Support sets up template accounts for your organization based on your requirements. You'll use the template account ID as the `templateAccountId` field when creating evaluation accounts.

To find your template account ID:

1. From the Admin Dashboards in the environment (staging or production) that matches where you'll be creating accounts, click **Query Builder** on the left pane.
2. Choose `accounts` from the **Repository** drop-down.
3. Find accounts with "template account" names.
   * Typically a query like this works: `name like "(?ium).*5K" OR name like "(?ium).*0K"` (query examples [production](https://dashboards.tradovate.com/query-builder?asc=false\&ids=\&limit=10000\&masterIds=\&orderBy=id\&queryType=regular\&recentPeriodSeconds=\&repository=accounts\&selection=id%20name%20active%20evaluationSize%20readonly%20organization%20customerApplicationId%20accountType%20marginAccountType%20legalStatus%20archived%20cashAmount%20dollarOpenPL%20dollarTotalPL%20netLiq%20initialMargin%20maintenanceMargin%20marginToEquity%20dayMargin%20totalUsedMargin%20totalAvailableMargin%20positionMargin%20availablePositionMargin%20liqOnlyLevel%20distToLiqOnly%20autoLiqLevel%20distToAutoLiq%20exposedPos%20hasPosition%20autorenewal%20membership%20membershipExpiration%20accountStatus%20dailyProfitLimit%20weeklyProfitLimit%20dailyLossLimit%20distToDailyLossLimit%20dailyLossLimitPercentage%20weekLoss%20weeklyLossLimit%20distToWeeklyLossLimit%20weeklyLossLimitPercentage%20trailingMaxDrawdown%20maxNetLiq%20drawdownAutoLiqLevel%20distDrawdownNetLiq%20customSalesCode%20migratedName%20customVendorId%20customVendorName%20ccEmail%20clearingHouse%20%7B%20name%20%7D%20riskCategory%20%7B%20name%20%7D%20autoLiqProfile%20%7B%20name%20%7D%20riskStatus%20%7B%20adminAction%20adminActionReasonCode%20approvalDeadline%20liquidateOnly%20autoLiqStarted%20autoLiqStopped%20totalLiqFee%20autoLiqCounter%20autoLiqDailyCounter%20autoLiqEmergencyMode%20autoLiqEmergencyMultiplier%20maxNetLiq%20maxNetLiqTimestamp%20notes%20notesExpiration%20%7D\&where=name%20like%20%22%28%3Fium%29.%2A5K%22%20OR%20name%20like%20%22%28%3Fium%29.%2A0K%22), [staging](https://dashboards.staging.ninjatrader.dev/query-builder?asc=false\&ids=\&limit=10000\&masterIds=\&orderBy=id\&queryType=regular\&recentPeriodSeconds=\&repository=accounts\&selection=id%20name%20active%20evaluationSize%20readonly%20organization%20customerApplicationId%20accountType%20marginAccountType%20legalStatus%20archived%20cashAmount%20dollarOpenPL%20dollarTotalPL%20netLiq%20initialMargin%20maintenanceMargin%20marginToEquity%20dayMargin%20totalUsedMargin%20totalAvailableMargin%20positionMargin%20availablePositionMargin%20liqOnlyLevel%20distToLiqOnly%20autoLiqLevel%20distToAutoLiq%20exposedPos%20hasPosition%20autorenewal%20membership%20membershipExpiration%20accountStatus%20dailyProfitLimit%20weeklyProfitLimit%20dailyLossLimit%20distToDailyLossLimit%20dailyLossLimitPercentage%20weekLoss%20weeklyLossLimit%20distToWeeklyLossLimit%20weeklyLossLimitPercentage%20trailingMaxDrawdown%20maxNetLiq%20drawdownAutoLiqLevel%20distDrawdownNetLiq%20customSalesCode%20migratedName%20customVendorId%20customVendorName%20ccEmail%20clearingHouse%20%7B%20name%20%7D%20riskCategory%20%7B%20name%20%7D%20autoLiqProfile%20%7B%20name%20%7D%20riskStatus%20%7B%20adminAction%20adminActionReasonCode%20approvalDeadline%20liquidateOnly%20autoLiqStarted%20autoLiqStopped%20totalLiqFee%20autoLiqCounter%20autoLiqDailyCounter%20autoLiqEmergencyMode%20autoLiqEmergencyMultiplier%20maxNetLiq%20maxNetLiqTimestamp%20notes%20notesExpiration%20%7D\&where=name%20like%20%22%28%3Fium%29.%2A5K%22%20OR%20name%20like%20%22%28%3Fium%29.%2A0K%22))

#### What Information is Needed to Build My Templates?

If you don't already have template accounts set up for your organization, reach out to Evaluation Support. To create a template account or set of template accounts, provide the following:

* A name for the account template
* Lot limits for the account type, such as how many E-mini or Micro contracts the account can hold at maximum
* Restricted products. You can restrict access to any products, product categories, or even whole exchanges for an account type.
* Liquidation time. By default, automatic liquidation is set between 4:00 PM and 5:00 PM CT, but you can specify something more specific (or edit the value yourself after creation via `RiskTimePeriod`).

---

## Step 1: Create Your Users

Call [`/user/createEvaluationUsers`](/api/rest-api-endpoints/users/create-evaluation-users) to create new users (up to 100 in a single request). Use the Tradovate Subscription Plan ID from [Prerequisites](#prerequisites) as the `tradovateSubscriptionPlanId` field.

This endpoint handles user registration and Tradovate subscription assignment in a single call; you don't need to call `signUpOrganizationMember` or `addTradovateSubscription` separately.

**Endpoint:** [`POST /user/createEvaluationUsers`](/api/rest-api-endpoints/users/create-evaluation-users)

**Environments:** Live

### Request Parameters

### Request

POST [https://demo.tradovateapi.com/v1/user/createevaluationusers](https://demo.tradovateapi.com/v1/user/createevaluationusers)

```curl
curl -X POST https://demo.tradovateapi.com/v1/user/createevaluationusers \
     -H "Authorization: Bearer <token>" \
     -H "Content-Type: application/json" \
     -d '{
  "users": [
    {
      "name": "string",
      "email": "string",
      "password": "string",
      "firstName": "string",
      "lastName": "string"
    }
  ]
}'
```

```python
import requests

url = "https://demo.tradovateapi.com/v1/user/createevaluationusers"

payload = { "users": [
        {
            "name": "string",
            "email": "string",
            "password": "string",
            "firstName": "string",
            "lastName": "string"
        }
    ] }
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript
const url = 'https://demo.tradovateapi.com/v1/user/createevaluationusers';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"users":[{"name":"string","email":"string","password":"string","firstName":"string","lastName":"string"}]}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://demo.tradovateapi.com/v1/user/createevaluationusers"

	payload := strings.NewReader("{\n  \"users\": [\n    {\n      \"name\": \"string\",\n      \"email\": \"string\",\n      \"password\": \"string\",\n      \"firstName\": \"string\",\n      \"lastName\": \"string\"\n    }\n  ]\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://demo.tradovateapi.com/v1/user/createevaluationusers")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"users\": [\n    {\n      \"name\": \"string\",\n      \"email\": \"string\",\n      \"password\": \"string\",\n      \"firstName\": \"string\",\n      \"lastName\": \"string\"\n    }\n  ]\n}"

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://demo.tradovateapi.com/v1/user/createevaluationusers")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"users\": [\n    {\n      \"name\": \"string\",\n      \"email\": \"string\",\n      \"password\": \"string\",\n      \"firstName\": \"string\",\n      \"lastName\": \"string\"\n    }\n  ]\n}")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://demo.tradovateapi.com/v1/user/createevaluationusers', [
  'body' => '{
  "users": [
    {
      "name": "string",
      "email": "string",
      "password": "string",
      "firstName": "string",
      "lastName": "string"
    }
  ]
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://demo.tradovateapi.com/v1/user/createevaluationusers");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"users\": [\n    {\n      \"name\": \"string\",\n      \"email\": \"string\",\n      \"password\": \"string\",\n      \"firstName\": \"string\",\n      \"lastName\": \"string\"\n    }\n  ]\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = ["users": [
    [
      "name": "string",
      "email": "string",
      "password": "string",
      "firstName": "string",
      "lastName": "string"
    ]
  ]] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://demo.tradovateapi.com/v1/user/createevaluationusers")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: \{ (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

### Response

### Response (200)

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

> **Info**
>
> Store the returned `userId` and map it to your internal user records. You'll need it for subsequent operations.

> **Warning**
>
> The [`createEvaluationUsers`](/api/rest-api-endpoints/users/create-evaluation-users) endpoint accepts an `entitlementIds` field, but do not pass Sim+ entitlement IDs (such as T-Prop) here. The entitlement must be assigned using the `addEntitlementSubscription` endpoint after the user signs the Market Data Agreement. See [Step 5](#step-5-add-the-t-prop-entitlement) for details.

---

## Step 2: Add Contact Information

Add contact information for the user. If you skip this step, the user will be prompted to enter it on their first login.

**Endpoint:** `POST /contactInfo/updateContactInfo`

**Environments:** Live

### Request Parameters

### Key Requirements

* **State**: Only required when `country == "US"`
* **Country**: Use two-letter country codes (Alpha-2 format)
* **Phone**: String format supporting international prefixes

---

## Step 3: Create Evaluation Accounts

From the `demo-api` (staging) or `demo` (production) domain, call [`createEvaluationAccounts`](/api/rest-api-endpoints/users/create-evaluation-accounts) to create new accounts and automatically assign them to users by user ID.

Use the Template Account ID from [Prerequisites](#prerequisites) as the `templateAccountId` field.

Each account's `name` must use uppercase letters followed by digits (e.g., `TESTACCOUNT123`). See [`createEvaluationAccounts`](/api/rest-api-endpoints/users/create-evaluation-accounts) for details.

**Endpoint:** [`POST /user/createEvaluationAccounts`](/api/rest-api-endpoints/users/create-evaluation-accounts)

**Environments:** Demo

### Request

POST [https://demo.tradovateapi.com/v1/user/createevaluationaccounts](https://demo.tradovateapi.com/v1/user/createevaluationaccounts)

```curl
curl -X POST https://demo.tradovateapi.com/v1/user/createevaluationaccounts \
     -H "Authorization: Bearer <token>" \
     -H "Content-Type: application/json" \
     -d '{
  "accounts": [
    {
      "userId": 12345,
      "templateAccountId": 67890,
      "name": "SIMACCOUNT001",
      "initialBalance": 100000
    }
  ]
}'
```

```python
import requests

url = "https://demo.tradovateapi.com/v1/user/createevaluationaccounts"

payload = { "accounts": [
        {
            "userId": 12345,
            "templateAccountId": 67890,
            "name": "SIMACCOUNT001",
            "initialBalance": 100000
        }
    ] }
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript
const url = 'https://demo.tradovateapi.com/v1/user/createevaluationaccounts';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"accounts":[{"userId":12345,"templateAccountId":67890,"name":"SIMACCOUNT001","initialBalance":100000}]}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://demo.tradovateapi.com/v1/user/createevaluationaccounts"

	payload := strings.NewReader("{\n  \"accounts\": [\n    {\n      \"userId\": 12345,\n      \"templateAccountId\": 67890,\n      \"name\": \"SIMACCOUNT001\",\n      \"initialBalance\": 100000\n    }\n  ]\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://demo.tradovateapi.com/v1/user/createevaluationaccounts")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"accounts\": [\n    {\n      \"userId\": 12345,\n      \"templateAccountId\": 67890,\n      \"name\": \"SIMACCOUNT001\",\n      \"initialBalance\": 100000\n    }\n  ]\n}"

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://demo.tradovateapi.com/v1/user/createevaluationaccounts")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"accounts\": [\n    {\n      \"userId\": 12345,\n      \"templateAccountId\": 67890,\n      \"name\": \"SIMACCOUNT001\",\n      \"initialBalance\": 100000\n    }\n  ]\n}")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://demo.tradovateapi.com/v1/user/createevaluationaccounts', [
  'body' => '{
  "accounts": [
    {
      "userId": 12345,
      "templateAccountId": 67890,
      "name": "SIMACCOUNT001",
      "initialBalance": 100000
    }
  ]
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://demo.tradovateapi.com/v1/user/createevaluationaccounts");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"accounts\": [\n    {\n      \"userId\": 12345,\n      \"templateAccountId\": 67890,\n      \"name\": \"SIMACCOUNT001\",\n      \"initialBalance\": 100000\n    }\n  ]\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = ["accounts": [
    [
      "userId": 12345,
      "templateAccountId": 67890,
      "name": "SIMACCOUNT001",
      "initialBalance": 100000
    ]
  ]] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://demo.tradovateapi.com/v1/user/createevaluationaccounts")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: \{ (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

### Response (200)

```json
{
  "results": [
    {
      "errorText": "",
      "accountId": 98765,
      "tradingPermissionId": 54321
    }
  ],
  "errorText": ""
}
```

The response includes a `tradingPermissionId`. This endpoint creates the account and assigns a trading permission in one operation.

> **Tip**
>
> Include `preTradeRisk` and `postTradeRisk` fields in your [`createEvaluationAccounts`](/api/rest-api-endpoints/users/create-evaluation-accounts) request when applicable. This reduces the number of API calls compared to making a separate call to `userAccountAutoLiq/update` after account creation.

> **Warning**
>
> Values such as daily loss limits or trailing drawdown are set via [Post-Trade Risk](/overview/prop-firm-management/risk-management/post-trade-risk), and aren't defined at the template level. You must set these values at the time of account creation.

---

## Step 4: Confirm the Market Data Agreement Signature

Before you can assign the T-Prop entitlement, users must sign the non-professional Market Data Agreement. There are two ways to detect when a user signs:

\<Tabs>

#### WebSocket

**Endpoint:** `POST /user/syncrequest`

To receive Market Data Agreement signature events in real time, set up a [WebSocket](/overview/core-concepts/web-sockets/connection-overview) and perform a [`syncRequest`](/api/rest-api-endpoints/users/sync-request).

### Request

POST [https://demo.tradovateapi.com/v1/user/syncrequest](https://demo.tradovateapi.com/v1/user/syncrequest)

```curl
curl -X POST https://demo.tradovateapi.com/v1/user/syncrequest \
     -H "Authorization: Bearer <token>" \
     -H "Content-Type: application/json" \
     -d '{}'
```

```python
import requests

url = "https://demo.tradovateapi.com/v1/user/syncrequest"

payload = {}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript
const url = 'https://demo.tradovateapi.com/v1/user/syncrequest';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://demo.tradovateapi.com/v1/user/syncrequest"

	payload := strings.NewReader("{}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://demo.tradovateapi.com/v1/user/syncrequest")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{}"

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://demo.tradovateapi.com/v1/user/syncrequest")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{}")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://demo.tradovateapi.com/v1/user/syncrequest', [
  'body' => '{}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://demo.tradovateapi.com/v1/user/syncrequest");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://demo.tradovateapi.com/v1/user/syncrequest")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: \{ (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

You can then listen for messages like the following:

```json
[
  {
    "e": "props",
    "d": [
      {
        "entityType": "OtherEnvAdminAlertSignal",
        "eventType": "Created",
        "entity": {
          "adminAlertSignal": {
            "id": 2179591,
            "timestamp": "2025-10-03T15:18:56.885Z",
            "adminAlertId": 70,
            "relatedToUserId": 29721,
            "text": "User TPropTestUser1001 signed non-professional market data form, <br />User name: Bill Rando <br />Date: 10/03/2025 <br />Timestamp: 2025-10-03 15:18:56 UTC <br />",
            "emailSent": false,
            "archived": false,
            "subjectId": 12081
          }
        }
      }
    ]
  }
]
```

> **Warning**
>
> In staging, use `adminAlertId=70`. In production, use `adminAlertId=68`.

\<Tab title="API">

**Endpoint:** `GET /adminAlertSignal/deps`

To retrieve all recent Market Data Agreement signatures for your organization, call `/adminAlertSignal/deps`.

In staging, use `/deps?masterid=70`. In production, use `/deps?masterid=68`. The `custapp:nonpro-signed` event ID is different in the two environments.

> **Note**
>
> The `/adminAlertSignal/deps` endpoint only returns recent signals. Signals are archived at the end of each week, so you'll only see data from the current week. If you need historical records, use BigQuery.

> **Warning**
>
> Do not poll `/adminAlertSignal/deps` on a schedule. You will eventually hit the rate limit and the operation will fail. Instead, use a WebSocket to receive signature events in real time.

\<End### Request

GET [https://demo.tradovateapi.com/v1/adminAlertSignal/deps](https://demo.tradovateapi.com/v1/adminAlertSignal/deps)

```curl
curl -G https://demo.tradovateapi.com/v1/adminAlertSignal/deps \
     -H "Authorization: Bearer <token>" \
     -H "Content-Type: application/json" \
     -d masterid=12345
```

```python
import requests

url = "https://demo.tradovateapi.com/v1/adminAlertSignal/deps"

querystring = {"masterid":"12345"}

payload = {}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.get(url, json=payload, headers=headers, params=querystring)

print(response.json())
```

```javascript
const url = 'https://demo.tradovateapi.com/v1/adminAlertSignal/deps?masterid=12345';
const options = {
  method: 'GET',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://demo.tradovateapi.com/v1/adminAlertSignal/deps?masterid=12345"

	payload := strings.NewReader("{}")

	req, _ := http.NewRequest("GET", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://demo.tradovateapi.com/v1/adminAlertSignal/deps?masterid=12345")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{}"

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.get("https://demo.tradovateapi.com/v1/adminAlertSignal/deps?masterid=12345")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{}")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://demo.tradovateapi.com/v1/adminAlertSignal/deps?masterid=12345', [
  'body' => '{}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://demo.tradovateapi.com/v1/adminAlertSignal/deps?masterid=12345");
var request = new RestRequest(Method.GET);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

````swift
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://demo.tradovateapi.com/v1/adminAlertSignal/deps?masterid=12345")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: \{ (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```Tab></Tabs>

---

## Step 5: Add the T-Prop Entitlement

After the system confirms the user has contact info and has signed the Market Data Agreement, assign the T-Prop entitlement.

If you call `addEntitlementSubscription` before the user signs the Market Data Agreement, the call fails. It returns an `HTTP 200` with the `errorText` "Live account is required", meaning the user hasn't signed the Market Data Agreement yet.

**Endpoint:** `POST /userPlugin/addEntitlementSubscription`

**Environments:** Live

<End### Request

POST https://demo.tradovateapi.com/v1/userPlugin/addentitlementsubscription

```curl
curl -X POST https://demo.tradovateapi.com/v1/userPlugin/addentitlementsubscription \
     -H "Authorization: Bearer <token>" \
     -H "Content-Type: application/json" \
     -d '{
  "entitlementId": 1
}'
````

```python
import requests

url = "https://demo.tradovateapi.com/v1/userPlugin/addentitlementsubscription"

payload = { "entitlementId": 1 }
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript
const url = 'https://demo.tradovateapi.com/v1/userPlugin/addentitlementsubscription';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"entitlementId":1}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://demo.tradovateapi.com/v1/userPlugin/addentitlementsubscription"

	payload := strings.NewReader("{\n  \"entitlementId\": 1\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://demo.tradovateapi.com/v1/userPlugin/addentitlementsubscription")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"entitlementId\": 1\n}"

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://demo.tradovateapi.com/v1/userPlugin/addentitlementsubscription")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"entitlementId\": 1\n}")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://demo.tradovateapi.com/v1/userPlugin/addentitlementsubscription', [
  'body' => '{
  "entitlementId": 1
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://demo.tradovateapi.com/v1/userPlugin/addentitlementsubscription");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"entitlementId\": 1\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

````swift
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = ["entitlementId": 1] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://demo.tradovateapi.com/v1/userPlugin/addentitlementsubscription")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: \{ (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```# Restricted Countries

Per CME Group policy, market data must not be accessed, distributed, or consumed in certain countries and regions.

---

## Revoking and Canceling

When users fail evaluations or leave your program:

1. **Revoke trading permissions** to remove access to specific accounts
2. **Cancel subscriptions** to stop platform access and billing

See [Revoke and Cancel Users and Accounts](./revoke-and-cancel-users-and-accounts) for detailed instructions.

---

## Next Steps

After you've created users and provisioned their accounts, continue with:

1. **[Risk Management Setup](./risk-management-setup)**: Configure account risk parameters
2. **[Market Data Renewals](/resources/reference/market-data-renewals)**: Automatic renewals for market data subscriptions
````