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.
Operations
Section titled “Operations”| 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.
Headers
Section titled “Headers”| 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.
List: GET /copy-trade/configs
Section titled “List: GET /copy-trade/configs”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/.
Create: POST /copy-trade/configs
Section titled “Create: POST /copy-trade/configs”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/.
linked_wallets
Section titled “linked_wallets”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 insideconfig.
Target wallet uniqueness
Section titled “Target wallet uniqueness”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).
Example: create
Section titled “Example: create”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" }}Get: GET /copy-trade/configs/{id}
Section titled “Get: GET /copy-trade/configs/{id}”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.
Patch: PATCH /copy-trade/configs/{id}
Section titled “Patch: PATCH /copy-trade/configs/{id}”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.
Python: replace linked_wallets
Section titled “Python: replace linked_wallets”import osimport 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 and resume
Section titled “Pause and resume”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.
Example: resume
Section titled “Example: resume”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.
Delete: DELETE /copy-trade/configs/{id}
Section titled “Delete: DELETE /copy-trade/configs/{id}”Needs copytrade:delete and If-Match. Active configurations cannot be deleted; pause first. Success is 204 with no body.
Lifecycle
Section titled “Lifecycle”- Create (paused) with
Idempotency-Key; keep theETag. - Resume with that
ETag. - For
configorlinked_walletschanges: pause, PATCH with full values, resume. remarkandrisk_label_idcan change at any time with the latestIf-Match.- To remove: pause, then delete.
Response envelope and errors
Section titled “Response envelope and errors”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.