Skip to content

X-Trader copy-trade configs API

The copy-trade configs API is the set of seven operations under /copy-trade/configs that manage the caller’s own copy-trade tasks: list, create, get, patch, delete, pause and resume. Each configuration follows one target_wallet, can carry up to 20 linked_wallets, and is always created paused (is_active=false) until POST /copy-trade/configs/{id}/resume. Reads need copytrade:read, writes copytrade:write, delete copytrade:delete.

Primary source: X-Trader API reference. This page is an independent explanation of X-Trader Public API v1.0.0; it is not affiliated with X-Trader.

Method and path Purpose Scope Required headers Success
GET /copy-trade/configs List owned configurations copytrade:read Authorization 200 list envelope
POST /copy-trade/configs Create a paused configuration copytrade:write Authorization, Idempotency-Key 201 resource envelope
GET /copy-trade/configs/{id} Read one configuration copytrade:read Authorization 200 resource envelope
PATCH /copy-trade/configs/{id} Update mutable fields copytrade:write Authorization, If-Match 200 resource envelope
DELETE /copy-trade/configs/{id} Delete a paused configuration copytrade:delete Authorization, If-Match 204 no body
POST /copy-trade/configs/{id}/pause Stop execution copytrade:write Authorization, If-Match 200 resource envelope
POST /copy-trade/configs/{id}/resume Revalidate and start execution copytrade:write Authorization, If-Match 200 resource envelope

Base URL: https://x-trader.ai/api/v1. Every operation also lists 400, 401, 403, 404, 409, 429, 500 and 503. Bulk delete is not available. Note the scope spelling: copytrade:* without a hyphen, while the path uses copy-trade.

Header Where Rule
Authorization All requests Bearer xt_live_<id>.<secret>
Idempotency-Key POST /copy-trade/configs Required. 8-128 characters from A-Z a-z 0-9 . _ : -, kept 24 hours. Same key with a different body: idempotency_conflict.
If-Match PATCH, DELETE, pause, resume Required. Latest ETag, format "v<number>". Stale value: version_conflict.
ETag (response) 201 and 200 single-resource responses Version to send on the next write
X-Request-Id (response) Single-resource and delete responses Support correlation ID

See /xtrader/write-rules/ for body size, decimal-string and strict-object rules.

Only the token owner’s configurations, ordered by updated_at and id.

Query parameter Type Rule
limit integer 1-100, default 20
cursor string Max 2048 characters; pass next_cursor unchanged. Bound to token and filters.
status string active or paused
q string Max 64 characters; searches remark and target_wallet
label_id string Owned label UUID or unlabeled; foreign or missing UUID returns 404

Response: data.items (array of CopyTradeResource), data.next_cursor (string or null), meta.request_id. See /xtrader/pagination/.

Body (CopyTradeCreate). Strict object; user_id, version, template and any unknown field are rejected.

Field Type Required Rule
remark string yes (default "") Max 64 characters, trimmed
target_wallet string yes Solana address, 32-44 characters. The wallet being copied. Immutable after creation.
linked_wallets array of string yes (default []) Max 20 items, each a unique Solana address of 32-44 characters
risk_label_id string (UUID) or null no Label owned by the account; see /xtrader/labels/
config object yes Complete copy-trade strategy; field reference at /xtrader/config-copy-trade/

Required keys in config: buy_config_mode, buy_config_universal, buy_config_tiers, selected_dexes, dex_source, buy_token_once, first_buy_only, reentry_after_flat, buy_once, skip_dev_launch, dev_sell_only, dev_sell_all_only, address_blacklist, min_trade_amount, max_trade_amount, auto_sell, auto_strategy, timed_strategy. Sell-side objects: /xtrader/auto-sell/, /xtrader/auto-strategy/, /xtrader/timed-strategy/.

The spec defines linked_wallets as unique Solana addresses linked to the copy-trade target, with a maximum of 20. It does not further describe how execution uses them. Rules that follow from the schema and operation text:

  • Duplicates inside the array are not allowed (the items must be unique).
  • On PATCH the array replaces the stored array completely; it is not appended to.
  • Changing it requires the configuration to be paused.
  • Do not confuse it with config.address_blacklist.wallets (max 50), which is a separate copy-trade filter inside config.

The error enum contains target_already_exists. The spec does not spell out the uniqueness scope; the code name indicates that the target_wallet already has a configuration. Practical handling: search with GET /copy-trade/configs?q=<target_wallet>, then pause and PATCH the existing configuration instead of creating another. The created configuration also counts toward the shared configuration quota shown by GET /me (quota_exceeded when it is full).

Terminal window
curl --request POST 'https://x-trader.ai/api/v1/copy-trade/configs' \
--header "Authorization: Bearer $X_TRADER_API_TOKEN" \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: create-copy-20261016-001' \
--data '{
"remark": "Primary copy-trade target",
"target_wallet": "11111111111111111111111111111111",
"linked_wallets": [],
"config": {
"buy_config_mode": "universal",
"buy_config_universal": {
"market_cap_min": "", "market_cap_max": "", "amount_sol": "0.1",
"jito_tip": "0.01", "jito_priority_fee": "0.0005", "jito_slippage": "15", "jito_bundle_amount": "",
"priority_fee": "0.005", "priority_tip": "0.001", "priority_slippage": "15", "priority_bundle_amount": "",
"sol_slippage_mode": false
},
"buy_config_tiers": [],
"selected_dexes": ["pump-fun"],
"dex_source": "global",
"buy_token_once": false,
"first_buy_only": false,
"reentry_after_flat": false,
"buy_once": false,
"skip_dev_launch": false,
"dev_sell_only": false,
"dev_sell_all_only": false,
"address_blacklist": {"enabled": false, "wallets": []},
"min_trade_amount": "",
"max_trade_amount": "",
"auto_sell": {
"enabled": false, "tab": "tpsl", "expiry_time": "10",
"tp_orders": [{"trigger": "90", "sell": "100"}], "sl_orders": [],
"follow_sell": false, "proportional_sell": false,
"trailing_take_profit": {"enabled": false, "tiers": []}
},
"auto_strategy": {"migration_clear": false, "timed_sell": false, "sell_delay": "30"},
"timed_strategy": {"enabled": false, "orders": []}
}
}'

Response 201 Created (headers ETag: "v1", X-Request-Id; IDs and timestamps illustrative):

{
"data": {
"id": "7a1c2e9d-0b3f-4d6a-8e5c-2f9b1d7a4c60",
"remark": "Primary copy-trade target",
"target_wallet": "11111111111111111111111111111111",
"is_active": false,
"risk_label_id": null,
"version": 1,
"created_at": "2026-10-16T09:00:00Z",
"updated_at": "2026-10-16T09:00:00Z",
"linked_wallets": [],
"config": { "buy_config_mode": "universal", "...": "stored config as sent" }
},
"meta": {
"request_id": "req_0123456789abcdef",
"persistence": "committed",
"propagation": "eventual"
}
}

id is a UUID. Missing IDs and IDs owned by other users both return 404 not_found. The stored snapshot is returned as is and may include legacy web-UI fields; create, update and resume still enforce the current strict schema.

Body (CopyTradePatch): at least one of remark, linked_wallets, risk_label_id, config.

Field Allowed while active Behaviour
remark yes Replaces the note
risk_label_id yes Binds a label; null unassigns
linked_wallets no, pause first Replaces the whole array (max 20)
config no, pause first Replaces the whole config; must pass the full schema
target_wallet never Immutable, not part of the patch schema

The error enum provides config_must_be_paused for writes that require a paused configuration.

import os
import requests
BASE = "https://x-trader.ai/api/v1"
H = {"Authorization": f"Bearer {os.environ['X_TRADER_API_TOKEN']}"}
cid = "7a1c2e9d-0b3f-4d6a-8e5c-2f9b1d7a4c60"
r = requests.get(f"{BASE}/copy-trade/configs/{cid}", headers=H)
r.raise_for_status()
etag, was_active = r.headers["ETag"], r.json()["data"]["is_active"]
if was_active:
r = requests.post(f"{BASE}/copy-trade/configs/{cid}/pause", headers={**H, "If-Match": etag})
r.raise_for_status()
etag = r.headers["ETag"]
r = requests.patch(
f"{BASE}/copy-trade/configs/{cid}",
json={"linked_wallets": ["So11111111111111111111111111111111111111112"]},
headers={**H, "If-Match": etag},
)
r.raise_for_status()
etag = r.headers["ETag"]
if was_active:
r = requests.post(f"{BASE}/copy-trade/configs/{cid}/resume", headers={**H, "If-Match": etag})
r.raise_for_status()

Pause changes the stored state immediately; execution nodes observe it eventually. Resume revalidates the full stored config before activation and refuses invalid historical data. Both take no body and require If-Match.

Terminal window
curl --request POST 'https://x-trader.ai/api/v1/copy-trade/configs/7a1c2e9d-0b3f-4d6a-8e5c-2f9b1d7a4c60/resume' \
--header "Authorization: Bearer $X_TRADER_API_TOKEN" \
--header 'If-Match: "v1"'

Response 200 OK (new ETag header; values illustrative):

{
"data": {
"id": "7a1c2e9d-0b3f-4d6a-8e5c-2f9b1d7a4c60",
"remark": "Primary copy-trade target",
"target_wallet": "11111111111111111111111111111111",
"is_active": true,
"risk_label_id": null,
"version": 2,
"created_at": "2026-10-16T09:00:00Z",
"updated_at": "2026-10-16T09:01:10Z",
"linked_wallets": [],
"config": { "buy_config_mode": "universal", "...": "unchanged stored config" }
},
"meta": {
"request_id": "req_0123456789abcdef",
"persistence": "committed",
"propagation": "eventual"
}
}

Use the returned ETag header for the next write instead of deriving it from version.

Needs copytrade:delete and If-Match. Active configurations cannot be deleted; pause first. Success is 204 with no body.

  1. Create (paused) with Idempotency-Key; keep the ETag.
  2. Resume with that ETag.
  3. For config or linked_wallets changes: pause, PATCH with full values, resume.
  4. remark and risk_label_id can change at any time with the latest If-Match.
  5. To remove: pause, then delete.

CopyTradeResource fields: id, remark, target_wallet, is_active, risk_label_id, version, created_at, updated_at, linked_wallets, config. Errors: { "error": { "code", "message", "fields"? }, "request_id" }.

Code Typical cause on /copy-trade/configs
validation_error Unknown field, more than 20 linked_wallets, duplicate or malformed address, JSON number instead of decimal string, failed resume revalidation
target_already_exists Target wallet already used by an existing configuration
insufficient_scope Missing copytrade:read, copytrade:write or copytrade:delete
not_found Unknown or foreign ID, foreign label
config_must_be_paused config or linked_wallets change, or delete, on an active configuration
version_conflict Stale If-Match
idempotency_required / idempotency_conflict Missing key, or key reused with another body
quota_exceeded Shared configuration quota full
rate_limit_exceeded, service_unavailable 429 / 503, honour Retry-After

The spec does not publish a mapping from each code to an HTTP status. See /xtrader/errors/.

How many linked_wallets can a copy-trade config have?

Section titled “How many linked_wallets can a copy-trade config have?”

Up to 20. Each entry is a unique Solana address of 32-44 characters, and the field defaults to an empty array.

What does target_already_exists mean on copy-trade create?

Section titled “What does target_already_exists mean on copy-trade create?”

It is the error code the API uses when the target wallet is already in use by an existing configuration. Find that configuration with GET /copy-trade/configs?q=<address> and update it instead of creating a second one.

Can I edit linked_wallets while the copy-trade is active?

Section titled “Can I edit linked_wallets while the copy-trade is active?”

No. Pause the configuration before changing config or linked_wallets. Only remark and risk_label_id can change while it is active.

Does PATCH linked_wallets add to the existing list?

Section titled “Does PATCH linked_wallets add to the existing list?”

No. linked_wallets in a PATCH replaces the whole stored array, so send the complete list you want to keep.

Which scopes does the copy-trade API need?

Section titled “Which scopes does the copy-trade API need?”

copytrade:read for list and get, copytrade:write for create, patch, pause and resume, and copytrade:delete for delete.