# X-Trader copy-trade config fields reference

URL: https://docs.blizz.id/xtrader/config-copy-trade/
Updated: 2026-10-16

A copy-trade body has `remark`, `target_wallet`, `linked_wallets` and `config` (all required on create) plus an optional `risk_label_id`. Inside `config`, buy size and execution fees live in `buy_config_universal` or in market-cap tiers under `buy_config_tiers`, selected by `buy_config_mode`. The rest of `config` holds the DEX selection, once-only switches, dev-launch and dev-sell modes, an address blacklist, trade-size filters and the three sell-side objects. All amounts, fees and percentages are decimal strings.

Primary source: [X-Trader API reference](https://x-trader.ai/api/docs). This page is an independent explanation of X-Trader Public API v1.0.0; it is not affiliated with X-Trader.

## Where these fields are used

| Operation | Schema | Body rules |
|---|---|---|
| `POST /copy-trade/configs` | `CopyTradeCreate` | `remark`, `target_wallet`, `linked_wallets`, `config` required. Needs `Idempotency-Key`. Created with `is_active=false`. |
| `PATCH /copy-trade/configs/{id}` | `CopyTradePatch` | Accepts `remark`, `linked_wallets`, `risk_label_id`, `config`; at least one. Needs `If-Match`. |

Every object is strict (`additionalProperties: false`): unknown keys return `validation_error`. Create also rejects `user_id`, `version` and `template`. General write rules are on [write rules](/xtrader/write-rules/); lifecycle calls on [copy-trade](/xtrader/copy-trade/).

## Top-level body fields

| Field | Type | Create | Patch | Limits and notes |
|---|---|---|---|---|
| `remark` | string | required (default `""`) | optional | Max 64 characters, trimmed. Free-text note. |
| `target_wallet` | string | required | not allowed | Solana address, 32-44 characters. The wallet whose trades are copied. Immutable after creation. |
| `linked_wallets` | array of strings | required (default `[]`) | optional | Up to 20 unique Solana addresses (max 44 characters each; the PATCH schema also states min 32) tied to the same target. In PATCH it replaces the whole array and requires the task to be paused. |
| `risk_label_id` | string (UUID) or `null` | optional | optional | Label owned by the same account ([labels](/xtrader/labels/)). `null` unassigns. A foreign label returns `404 not_found`. |
| `config` | object | required | optional | Full strategy object. In PATCH it replaces the stored config and requires the task to be paused. |

Linked wallets matter for `skip_dev_launch`, `dev_sell_only` and `dev_sell_all_only`, which check whether the creator is the target or a linked wallet.

There is no template reference field. Templates are managed separately ([templates](/xtrader/templates/)); to use one, read its config and send it as `config`.

## Buy mode

| Field | Type | Required | Allowed values | Meaning |
|---|---|---|---|---|
| `buy_config_mode` | string enum | yes | `universal`, `tiered` | Which buy parameter set is active. |
| `buy_config_universal` | object | yes | strict object | One parameter set for all followed buys. |
| `buy_config_tiers` | array of objects | yes | max 20 items | Market-cap-specific parameter sets. |

Both `buy_config_universal` and `buy_config_tiers` must be present whatever the mode. Only the active side needs a real `amount_sol`; the inactive side may keep an empty string (universal) or an empty array (tiers).

| Mode | Active side | Requirements |
|---|---|---|
| `universal` | `buy_config_universal` | Its `amount_sol` must be > 0 and <= 1,000,000. `buy_config_tiers` may be `[]`. |
| `tiered` | `buy_config_tiers` | At least one tier, each with a valid `amount_sol`. `buy_config_universal` must still be sent; its `amount_sol` may be `""`. |

## Buy parameter set (universal object and each tier)

`buy_config_universal` and every element of `buy_config_tiers` share exactly the same fields. Unlike the sniper config, copy-trade has no `jito_mode` / `priority_mode` objects: the two execution channels are encoded as prefixed flat fields.

| Field | Type | Required | Limits | Meaning |
|---|---|---|---|---|
| `market_cap_min` | decimal string | yes | max length 32 | Lower market-cap bound. `""` means no lower bound. |
| `market_cap_max` | decimal string | yes | must not be below `market_cap_min` | Upper market-cap bound. `""` means no upper bound. |
| `amount_sol` | decimal string | yes | > 0 and <= 1,000,000 on the active side; `""` allowed on the unused side | SOL spent per copied buy. |
| `jito_tip` | decimal string | yes | 0 to 1,000 SOL | Jito channel tip. |
| `jito_priority_fee` | decimal string | yes | 0 to 1,000 SOL | Jito channel priority fee. |
| `jito_slippage` | decimal string | yes | 0 to 100 (percent) | Jito channel slippage. Ignored when `jito_bundle_amount` is positive on a DEX that supports bundle pool advancement. |
| `jito_bundle_amount` | decimal string | no | max length 32 | Jito-only bundle pressure in SOL. Empty or omitted means percentage slippage is used. |
| `priority_fee` | decimal string | yes | 0 to 1,000 SOL | Direct/leader channel priority fee. |
| `priority_tip` | decimal string | yes | 0 to 1,000 SOL | Direct/leader channel tip. |
| `priority_slippage` | decimal string | yes | 0 to 100 (percent) | Direct/leader channel slippage. Ignored when `priority_bundle_amount` is positive on a DEX that supports bundle pool advancement. |
| `priority_bundle_amount` | decimal string | no | max length 32 | Direct/leader-only bundle pressure in SOL. Empty or omitted means percentage slippage. |
| `selected_dexes` | array of strings | no | max 7, same enum as config-level list | Tier scope (see below). Unrelated to the config-level DEX setting. |
| `sol_slippage_mode` | boolean | yes | default `false` | Legacy shared SOL-slippage flag, kept for old configs. Prefer the two per-channel flags. |
| `jito_sol_slippage_mode` | boolean | no | | When `true`, the Jito channel uses SOL slippage and ignores `jito_slippage`. |
| `priority_sol_slippage_mode` | boolean | no | | Same for the direct/leader channel, independent of the Jito flag. |

Mapping to the sniper names, for readers coming from the [sniper config reference](/xtrader/config-sniper/):

| Sniper (`jito_mode.*` / `priority_mode.*`) | Copy-trade Jito channel | Copy-trade direct channel |
|---|---|---|
| `tip_amount` | `jito_tip` | `priority_tip` |
| `priority_fee` | `jito_priority_fee` | `priority_fee` |
| `slippage` | `jito_slippage` | `priority_slippage` |
| `bundle_amount` | `jito_bundle_amount` | `priority_bundle_amount` |
| `sol_slippage_mode` | `jito_sol_slippage_mode` | `priority_sol_slippage_mode` |

The spec does not document which channel a particular copied trade uses.

### How market-cap tiers work

| Rule | Source in spec |
|---|---|
| Up to 20 tiers. | `buy_config_tiers` `maxItems: 20` |
| Each tier is a range `market_cap_min` to `market_cap_max`; an empty bound is open. | field descriptions |
| `market_cap_max` must not be below `market_cap_min`. | field description |
| `selected_dexes` inside a tier narrows that tier to the listed DEXes; omitted or `[]` applies the tier to all DEXes. | `selected_dexes` description |
| In `tiered` mode at least one tier is required. | `buy_config_mode` description |

The spec does not document the market-cap unit (SOL or USD), the order in which tiers are evaluated, how overlapping ranges are resolved, or what happens when a token's market cap matches no tier. Non-overlapping ranges avoid the ambiguity; an open-ended tier (`""` on one side) covers the edges.

## DEX selection

| Field | Type | Required | Allowed values | Meaning |
|---|---|---|---|---|
| `selected_dexes` | array of strings | yes | 1 to 7 of `pump-fun`, `pump-amm`, `launchlab`, `meteora-dynamic-bc`, `meteora-damm-v2`, `raydium-amm`, `raydium-cpmm` | DEXes on which the target's trades are followed. |
| `dex_source` | string enum | yes (default `global`) | `global`, `config` | `global`: the account's enabled global DEX list, falling back to `selected_dexes` when that list is unavailable. `config`: always `selected_dexes`. |

`dev_sell_only` and `dev_sell_all_only` require `pump-fun` in `selected_dexes`.

## Once-only switches

| Field | Type | Required | Default | Scope | Meaning |
|---|---|---|---|---|---|
| `buy_token_once` | boolean | yes | none | per token | Each token is bought at most once by this config. An attempted buy counts even if execution fails. |
| `first_buy_only` | boolean | yes | none | per target | The task reacts only once for the target address. Filtered, failed and successful normal signals all count. In `dev_sell_only` mode, the first successfully submitted dev-sell buy blocks later dev sells from triggering. |
| `buy_once` | boolean | yes | none | whole task | The task deactivates after its first triggered trade. |
| `reentry_after_flat` | boolean | yes | `false` | | Deprecated. `true` is treated as `first_buy_only=true` and stored as `false`. Send `false` and use `first_buy_only`. |

## Creator (dev) modes

| Field | Type | Required | Default | Meaning |
|---|---|---|---|---|
| `skip_dev_launch` | boolean | yes | `false` | Skip Pump, Launchpad and DBC bonding-curve tokens whose creator is the target or a linked wallet. Historical tokens without creator data are not skipped. |
| `dev_sell_only` | boolean | yes | `false` | Normal buys are not followed. A buy is triggered only when the target or a linked wallet is the creator and sells a Pump bonding-curve token. |
| `dev_sell_all_only` | boolean | yes | `false` | Normal buys are not followed. A buy is triggered only when the creator's Pump sell leaves its source token account at zero. |

Documented side effects and limits:

| Mode | Notes |
|---|---|
| `dev_sell_only` | `pump-fun` must be selected. `min_trade_amount`, `max_trade_amount`, Anti-PVP and `skip_dev_launch` are ignored. Address-index changes can take up to 10 seconds. Historical pools without creator data are skipped. |
| `dev_sell_all_only` | `pump-fun` must be selected. Can be combined with `dev_sell_only`. One exit transaction triggers only one buy. If the post-trade balance cannot be verified, the signal is skipped. |

## Address blacklist

| Field | Type | Required | Default | Limits | Meaning |
|---|---|---|---|---|---|
| `address_blacklist` | object | yes | `{"enabled": false, "wallets": []}` | strict object | Copy-trade only filter. |
| `address_blacklist.enabled` | boolean | yes | `false` | | When `true`, a followed buy is skipped if any listed wallet bought the same mint earlier, within 24 hours of observation. |
| `address_blacklist.wallets` | array of strings | yes | `[]` | max 50, unique, valid Solana addresses (32-44 characters) | Wallets to check against. |

The spec notes that observation covers all configured wallets regardless of `enabled`, so wallets in a disabled list are still tracked.

## Trade-size filter

| Field | Type | Required | Limits | Meaning |
|---|---|---|---|---|
| `min_trade_amount` | decimal string | yes | max length 32 | Minimum size of the target's transaction to follow. `""` disables the lower bound. Ignored by `dev_sell_only`. |
| `max_trade_amount` | decimal string | yes | must not be below `min_trade_amount` unless `dev_sell_only` is on | Maximum size of the target's transaction to follow. `""` disables the upper bound. |

These filter the target's trade, not your buy size. The spec does not state the unit; the other amounts in the config are in SOL.

## Legacy field

| Field | Type | Required | Meaning |
|---|---|---|---|
| `bundle_amount` | decimal string | no | Legacy top-level bundle pressure fallback for old configs. Use `jito_bundle_amount` and `priority_bundle_amount` in the buy parameter sets. |

## Sell-side objects

| Field | Summary | Reference |
|---|---|---|
| `auto_sell` | Take-profit and stop-loss orders, trailing take-profit, follow-sell and proportional-sell, with an expiry in minutes (`0` keeps it active). | [auto-sell](/xtrader/auto-sell/) |
| `auto_strategy` | Extra exit rules: migration clear, timed sell, position and price-stagnation clears, profit and SL protection, phased SL, Anti-PVP and sell-fee override. | [auto-strategy](/xtrader/auto-strategy/) |
| `timed_strategy` | Staged time-based sell orders, maximum 20. | [timed-strategy](/xtrader/timed-strategy/) |

All three are required. Minimum accepted shapes: `auto_sell` with `enabled`, `expiry_time`, `tp_orders`, `sl_orders`, `follow_sell`, `proportional_sell`; `auto_strategy` with `migration_clear`, `timed_sell`, `sell_delay`; `timed_strategy` with `enabled` and `orders`.

## What differs in CopyTradePatch

| Aspect | CopyTradeCreate | CopyTradePatch |
|---|---|---|
| Required top-level fields | `remark`, `target_wallet`, `linked_wallets`, `config` | at least one of `remark`, `linked_wallets`, `risk_label_id`, `config` |
| `target_wallet` | required | not accepted |
| `linked_wallets` | required, default `[]` | optional; replaces the whole array; task must be paused |
| `config` | full object | full object again; replaces the stored config; task must be paused |
| Active task | n/a (created paused) | only `remark` and `risk_label_id` may change |
| Headers | `Idempotency-Key` | `If-Match` with the latest ETag |

The nested `config` schema is identical in both operations.

## Minimal valid create body

Universal mode, no filters, sell-side features off:

```json
{
  "remark": "",
  "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",
      "priority_fee": "0.005",
      "priority_tip": "0.001",
      "priority_slippage": "15",
      "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,
      "expiry_time": "0",
      "tp_orders": [],
      "sl_orders": [],
      "follow_sell": false,
      "proportional_sell": false
    },
    "auto_strategy": { "migration_clear": false, "timed_sell": false, "sell_delay": "30" },
    "timed_strategy": { "enabled": false, "orders": [] }
  }
}
```

## Fuller example: tiered mode with filters

Two market-cap tiers, a linked wallet, buy each token once, skip the target's own launches, a blacklist and a trade-size window. Addresses are placeholders.

```json
{
  "remark": "Tiered copy, main target",
  "target_wallet": "11111111111111111111111111111111",
  "linked_wallets": ["So11111111111111111111111111111111111111112"],
  "risk_label_id": "3f2c1a9e-8b7d-4c6e-9a1b-2d3e4f5a6b7c",
  "config": {
    "buy_config_mode": "tiered",
    "buy_config_universal": {
      "market_cap_min": "",
      "market_cap_max": "",
      "amount_sol": "",
      "jito_tip": "0",
      "jito_priority_fee": "0",
      "jito_slippage": "0",
      "priority_fee": "0",
      "priority_tip": "0",
      "priority_slippage": "0",
      "sol_slippage_mode": false
    },
    "buy_config_tiers": [
      {
        "market_cap_min": "",
        "market_cap_max": "50000",
        "amount_sol": "0.2",
        "jito_tip": "0.01",
        "jito_priority_fee": "0.0005",
        "jito_slippage": "25",
        "jito_bundle_amount": "",
        "priority_fee": "0.005",
        "priority_tip": "0.001",
        "priority_slippage": "25",
        "priority_bundle_amount": "",
        "selected_dexes": [],
        "sol_slippage_mode": false,
        "jito_sol_slippage_mode": false,
        "priority_sol_slippage_mode": false
      },
      {
        "market_cap_min": "50000",
        "market_cap_max": "",
        "amount_sol": "0.05",
        "jito_tip": "0.005",
        "jito_priority_fee": "0.0005",
        "jito_slippage": "10",
        "priority_fee": "0.003",
        "priority_tip": "0.001",
        "priority_slippage": "10",
        "selected_dexes": ["pump-amm", "raydium-cpmm"],
        "sol_slippage_mode": false
      }
    ],
    "selected_dexes": ["pump-fun", "pump-amm", "raydium-cpmm"],
    "dex_source": "config",
    "buy_token_once": true,
    "first_buy_only": false,
    "reentry_after_flat": false,
    "buy_once": false,
    "skip_dev_launch": true,
    "dev_sell_only": false,
    "dev_sell_all_only": false,
    "address_blacklist": {
      "enabled": true,
      "wallets": ["11111111111111111111111111111112"]
    },
    "min_trade_amount": "0.5",
    "max_trade_amount": "20",
    "auto_sell": {
      "enabled": true,
      "tab": "tpsl",
      "expiry_time": "120",
      "tp_orders": [{ "trigger": "90", "sell": "100" }],
      "sl_orders": [],
      "follow_sell": true,
      "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": [] }
  }
}
```

The inactive `buy_config_universal` keeps `amount_sol` empty, as the spec allows. Its fee fields are still required; this example fills them with `"0"`, which is inside the documented 0 to 1,000 and 0 to 100 ranges. The second tier relies on `market_cap_min` equal to the first tier's `market_cap_max`; since boundary handling is not documented, leave a gap or accept that one value may match either tier.

## Sending the body

```bash
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 @copy-config.json
```

```python
import json
import os

import requests

BASE = "https://x-trader.ai/api/v1"
auth = {"Authorization": f"Bearer {os.environ['X_TRADER_API_TOKEN']}"}

with open("copy-config.json") as f:
    body = json.load(f)

resp = requests.post(
    f"{BASE}/copy-trade/configs",
    json=body,
    headers={**auth, "Idempotency-Key": "create-copy-20261016-001"},
    timeout=30,
)
resp.raise_for_status()
config_id = resp.json()["data"]["id"]
etag = resp.headers["ETag"]
```

Replacing `linked_wallets` on a paused task:

```bash
curl --request PATCH "https://x-trader.ai/api/v1/copy-trade/configs/$CONFIG_ID" \
  --header "Authorization: Bearer $X_TRADER_API_TOKEN" \
  --header 'Content-Type: application/json' \
  --header 'If-Match: "v1"' \
  --data '{"linked_wallets":["So11111111111111111111111111111111111111112"]}'
```

```python
resp = requests.patch(
    f"{BASE}/copy-trade/configs/{config_id}",
    json={"linked_wallets": ["So11111111111111111111111111111111111111112"]},
    headers={**auth, "If-Match": etag},
    timeout=30,
)
resp.raise_for_status()
```

## FAQ

### What is the difference between universal and tiered buy_config_mode?

`universal` applies the single `buy_config_universal` parameter set to every followed buy. `tiered` uses `buy_config_tiers`, a list of up to 20 market-cap ranges each with its own amount, fees and slippage, and requires at least one tier.

### Do I have to send buy_config_tiers in universal mode?

Yes. Both `buy_config_universal` and `buy_config_tiers` are required keys in every config. In universal mode send an empty tiers array; in tiered mode the universal object stays but its `amount_sol` may be an empty string.

### What is the difference between buy_token_once, first_buy_only and buy_once?

`buy_token_once` buys each token at most once for the task. `first_buy_only` makes the task react only once for the target address. `buy_once` deactivates the whole task after its first triggered trade.

### Can I create a copy-trade config from a template through the API?

No template reference is accepted in the create body. The create endpoint rejects a `template` field together with `user_id`, `version` and unknown fields, so send the full config.

### What is required for dev_sell_only to work?

`pump-fun` must be in `selected_dexes`. The task then ignores normal buys and triggers only when the target or a linked wallet is the token creator and sells a Pump bonding-curve token.
