Update Copier
Change one or more fields of a trade copier. The change is validated as a whole before anything is saved.
The Management API requires an Elite subscription. See Authentication.
- NT8
- Tradovate
Endpoint
PATCH https://app.crosstrade.io/v1/api/manage/nt8/copiers/{id}
Headers
| Name | Required | Value |
|---|---|---|
| Authorization | Yes | Bearer <your API token> |
| Content-Type | Yes | application/json |
| If-Match | No | ETag from a previous read. The request fails with 412 if the copier changed since then |
Path parameters
| Name | Type | Description |
|---|---|---|
id | string | The copier id |
Body parameters
Send any writable field from Copier fields. Leave out what you do not want to change. Nested objects merge; arrays (followers, instruments) replace the saved array, and symbolReplacements replaces the saved map. To switch between single and group, send type, followers and groupName together: a group needs groupName and at least two followers, a single copier exactly one follower and groupName: null.
You can send back the whole object from a GET. Read-only fields (id, created, updated, followers[].environment) and fields this broker does not have are ignored when they equal the saved value (null for a field this broker does not have) and refused when they differ. updated is always ignored. If nothing differs, the response says changed: false. The whole object includes leader and followers, so on NinjaTrader this needs the add-on connected.
Code examples
- Python
- cURL
import requests
resp = requests.patch(
"https://app.crosstrade.io/v1/api/manage/nt8/copiers/4b1f0c9e2d7a4c55b1e0",
headers={"Authorization": "Bearer YOUR_TOKEN"},
json={'active': True, 'sizing': {'maxQuantity': 3}},
)
print(resp.status_code, resp.json())
curl -X PATCH "https://app.crosstrade.io/v1/api/manage/nt8/copiers/4b1f0c9e2d7a4c55b1e0" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"active": true, "sizing": {"maxQuantity": 3}}'
Responses
- 200
- Other errors
{
"success": true,
"changed": true,
"data": {
"id": "4b1f0c9e2d7a4c55b1e0",
"nickname": null,
"active": true,
"mode": "order",
"leader": "Sim101",
"type": "single",
"groupName": null,
"followers": [
{
"account": "DemoAccount"
}
],
"sizing": {
"method": "ratio",
"ratio": 1,
"quantity": null,
"maxQuantity": 3
},
"inverse": false,
"fillsOnly": false,
"instruments": [
"*"
],
"symbolReplacements": {},
"stealth": true,
"tandem": false,
"autoSync": {
"enabled": true,
"intervalSeconds": 10
},
"syncCorrection": {
"cooldownSeconds": 300,
"maxAttempts": 1
},
"reconnectDelayMs": 10000,
"strategyTagMode": "override",
"created": "2026-09-01T13:02:11Z",
"updated": "2026-10-02T14:31:07Z"
},
"changedFields": [
"active",
"sizing.maxQuantity"
],
"delivery": {
"status": "queued",
"target": "nt8_addon"
},
"warnings": [],
"meta": {
"requestId": "req_9f2c1a0b7d3e4f51",
"etag": "\"c2:Tm90UmVhbEV0YWcwMg\""
}
}
| Status | error | When |
|---|---|---|
| 400 | invalid_json | The body is not valid JSON |
| 400 | invalid_path | The id in the path is not valid |
| 401 | unauthorized | Missing or invalid token |
| 403 | elite_required, not_available | See Authentication |
| 404 | account_not_found | An account is not on your NinjaTrader connection (Backtest and Playback101 are never accepted) |
| 404 | not_found | No such copier on your login |
| 409 | addon_disconnected | leader, followers, type or groupName was sent, or a follower shared with another copier must be checked, while the add-on is not connected |
| 409 | addon_version_unsupported | Sharing a follower between copiers needs add-on v1.10.10 or newer |
| 409 | autosync_conflict | A shared follower would have overlapping instruments with Auto-Sync on |
| 409 | concurrent_modification | Another change to your copiers is in progress |
| 409 | copier_cycle | The copier would create a copy loop |
| 409 | duplicate_copier | A copier on the same leader and follower already covers these instruments |
| 409 | group_name_conflict | The group name matches one of your account names |
| 409 | tandem_requires_monitor | Tandem is on and a follower has no monitor |
| 412 | precondition_failed | If-Match did not match |
| 413 | body_too_large | The body is larger than 64 KB |
| 415 | unsupported_content_type | The body is not application/json |
| 422 | field_read_only, field_not_applicable | A read-only field, or a field this broker does not have, was sent with a value different from the saved one |
| 422 | invalid_replacement | A symbol replacement is not allowed |
| 422 | validation_failed | A field is invalid, or the combination breaks a rule (for example fillsOnly in execution mode, or a ratio that is not one of the allowed steps, code ratio_not_a_step) |
| 429 | rate_limited, too_many_concurrent_requests | See Rate limits |
| 503 | management_read_only, management_busy, storage_unavailable, outcome_unknown | See Errors |
Endpoint
PATCH https://app.crosstrade.io/v1/api/manage/tradovate/copiers/{id}
Headers
| Name | Required | Value |
|---|---|---|
| Authorization | Yes | Bearer <your API token> |
| Content-Type | Yes | application/json |
| If-Match | No | ETag from a previous read. The request fails with 412 if the copier changed since then |
Path parameters
| Name | Type | Description |
|---|---|---|
id | string | The copier id |
Body parameters
Send any writable field from Copier fields. Leave out what you do not want to change. Nested objects merge; arrays (followers, instruments) replace the saved array, and symbolReplacements replaces the saved map. To switch between single and group, send type, followers and groupName together: a group needs groupName and at least two followers, a single copier exactly one follower and groupName: null.
You can send back the whole object from a GET. Read-only fields (id, created, updated, followers[].environment) and fields this broker does not have are ignored when they equal the saved value (null for a field this broker does not have) and refused when they differ. updated is always ignored. If nothing differs, the response says changed: false.
Code examples
- Python
- cURL
import requests
resp = requests.patch(
"https://app.crosstrade.io/v1/api/manage/tradovate/copiers/9c3e5a7b1d2f4e6a8b0c",
headers={"Authorization": "Bearer YOUR_TOKEN"},
json={'active': True, 'sizing': {'maxQuantity': 3}},
)
print(resp.status_code, resp.json())
curl -X PATCH "https://app.crosstrade.io/v1/api/manage/tradovate/copiers/9c3e5a7b1d2f4e6a8b0c" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"active": true, "sizing": {"maxQuantity": 3}}'
Responses
- 200
- Other errors
{
"success": true,
"changed": true,
"data": {
"id": "9c3e5a7b1d2f4e6a8b0c",
"nickname": null,
"active": true,
"mode": "signal",
"leader": "DEMO12345678",
"type": "single",
"groupName": null,
"followers": [
{
"account": "DEMO87654321",
"environment": "demo"
}
],
"sizing": {
"method": "ratio",
"ratio": 1,
"quantity": null,
"maxQuantity": 3
},
"inverse": false,
"fillsOnly": false,
"instruments": [
"*"
],
"symbolReplacements": {},
"stealth": true,
"tandem": false,
"autoSync": {
"enabled": true
},
"syncCorrection": {
"cooldownSeconds": 300,
"maxAttempts": 1
},
"created": "2026-09-01T13:02:11Z",
"updated": "2026-10-02T14:31:07Z"
},
"changedFields": [
"active",
"sizing.maxQuantity"
],
"delivery": {
"status": "automatic",
"target": "tradovate_engine"
},
"warnings": [],
"meta": {
"requestId": "req_9f2c1a0b7d3e4f51",
"etag": "\"c2:Tm90UmVhbEV0YWcwMg\""
}
}
| Status | error | When |
|---|---|---|
| 400 | invalid_json | The body is not valid JSON |
| 400 | invalid_path | The id in the path is not valid |
| 401 | unauthorized | Missing or invalid token |
| 403 | elite_required, not_available | See Authentication |
| 403 | plan_required | The copier is on and your plan does not include the Tradovate copier |
| 404 | account_not_found | An account is not among your synced Tradovate accounts |
| 404 | not_found | No such copier on your login |
| 409 | account_identity_unresolved | An account could not be matched to your linked Tradovate login |
| 409 | concurrent_modification | Another change to your copiers is in progress |
| 409 | copier_cycle | The copier would create a copy loop |
| 409 | duplicate_copier | A copier on the same leader and follower already covers these instruments. For a copier that is on, adding a pair that any other copier links |
| 409 | follower_conflict, duplicate_follower | A follower is already copied by another active copier and one of the two uses Auto-Sync, or a follower is listed twice |
| 409 | limit_reached | The leader has the maximum number of active followers |
| 409 | tandem_requires_monitor | Tandem is on and a follower has no monitor |
| 409 | tradovate_not_linked | The copier is on and no Tradovate login is linked |
| 412 | precondition_failed | If-Match did not match |
| 413 | body_too_large | The body is larger than 64 KB |
| 415 | unsupported_content_type | The body is not application/json |
| 422 | field_read_only, field_not_applicable | A read-only field, or a field this broker does not have, was sent with a value different from the saved one |
| 422 | invalid_replacement | A symbol replacement is not allowed |
| 422 | validation_failed | A field is invalid, or the combination breaks a rule (for example fillsOnly in execution mode, or a ratio that is not one of the allowed steps, code ratio_not_a_step) |
| 429 | rate_limited, too_many_concurrent_requests | See Rate limits |
| 503 | management_read_only, management_busy, storage_unavailable, outcome_unknown | See Errors |
When it takes effect
NinjaTrader: sent to the add-on right after the save, or when it next connects. Tradovate: signal mode on the next signal, execution and order mode on the next fill. Turning on your first active Tradovate copier can take up to about 30 seconds.
Notes
{"active": false}is always accepted, even for a copier that breaks today's rules or while the add-on is disconnected. When the body is exactly{"active": false}, it uses a separatestopbudget (120 per minute, burst 60) that does not count toward your Changes or per-copier budgets, so you can turn off every copier at once. Anything else in the body makes it an ordinary change. See Turning copiers off quickly.- Turning a copier on, and every other change, uses the normal budgets: Changes (20 per minute, burst 10) and per copier (6 per minute, burst 3).
- Turning a NinjaTrader copier on while the add-on is offline is accepted (unless one of its followers is shared with another copier):
delivery.statusispending_connectionand the add-on picks it up when it reconnects. - Sending
leader,followers,typeorgroupNameto a NinjaTrader copier, even with unchanged values, checks the accounts with your add-on, so it needs the add-on connected (409 addon_disconnected). symbolReplacementsreplaces the whole map. Send the full set you want to keep, or{}to remove them all.- The copy-loop, duplicate and Auto-Sync checks run when you send
type,leader,followers,groupName,instrumentsorautoSync, or turn the copier on. They compare against all your copiers, including ones that are off. nickname: nullremoves the nickname.- Turning Auto-Sync off on NinjaTrader resets
syncCorrectionto 300 seconds and 1 attempt unless you sendsyncCorrectiontoo. - A save in the web app right after an API change can overwrite it.
If-Matchprotects against other API clients only.