# X-Trader sniper config fields reference

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

A sniper configuration body has three top-level fields (`remark`, `target_wallet`, `config`) plus an optional `risk_label_id`. The `config` object is strict: it requires `buy_amount`, the two execution objects `jito_mode` and `priority_mode`, the DEX selection (`selected_dexes`, `dex_source`), four booleans and the three sell-side objects `auto_sell`, `auto_strategy` and `timed_strategy`. All amounts, fees and percentages are decimal strings, never JSON numbers.

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 /sniper/configs` | `SniperCreate` | `remark`, `target_wallet`, `config` required. Needs `Idempotency-Key`. Created with `is_active=false`. |
| `PATCH /sniper/configs/{id}` | `SniperPatch` | At least one top-level field. Needs `If-Match`. `target_wallet` not accepted. |

Both schemas use `additionalProperties: false` at every level, so a misspelled or unknown key returns `validation_error` instead of being ignored. The create endpoint also rejects `user_id`, `version` and `template`. General write rules (64 KiB body limit, at most 12 fractional digits in decimal strings) are described in [write rules](/xtrader/write-rules/). Lifecycle calls (create, pause, resume, delete) are on the [sniper page](/xtrader/sniper/).

## Top-level body fields

| Field | Type | Create | Patch | Limits and notes |
|---|---|---|---|---|
| `remark` | string | required (default `""`) | optional | Max 64 characters. Leading and trailing spaces are trimmed. Free-text note; an empty string is valid. |
| `target_wallet` | string | required | not allowed | Solana address, 32-44 characters. The wallet whose launches the task snipes. Immutable after creation. |
| `risk_label_id` | string (UUID) or `null` | optional | optional | UUID of a label owned by the same account (see [labels](/xtrader/labels/)). `null` unassigns. A label of another account returns `404 not_found`. |
| `config` | object | required | optional | Full strategy object described below. In a PATCH it replaces the stored config entirely. |

## Buy size and execution channels

| Field | Type | Required | Limits | Meaning |
|---|---|---|---|---|
| `buy_amount` | decimal string | yes | > 0 and <= 1,000,000; max length 32 | SOL spent on each snipe buy. |
| `jito_mode` | object | yes | strict object | Fee and slippage settings for Jito execution. |
| `priority_mode` | object | yes | strict object | Fee and slippage settings for leader/direct execution. |
| `bundle_amount` | decimal string | no | max length 32 | Legacy top-level fallback for old configs. Use the nested `bundle_amount` inside each mode instead. |
| `sol_slippage_mode` | boolean | yes (default `false`) | | Legacy shared SOL-slippage flag, kept as a fallback for old configs. Prefer the per-mode `sol_slippage_mode`. |

### jito_mode and priority_mode sub-fields

`jito_mode` and `priority_mode` have an identical shape. Each is a separate set of values, so the Jito channel and the direct channel can have different tips, fees and slippage. Both objects must be present in every create body and in every PATCH that contains `config`. The spec does not document the rule that decides which channel is used for a particular trade.

| Sub-field | Type | Required | Limits | Meaning |
|---|---|---|---|---|
| `tip_amount` | decimal string | yes | 0 to 1,000 SOL | Tip paid with the transaction, in SOL. |
| `priority_fee` | decimal string | yes | 0 to 1,000 SOL | Priority fee, in SOL (not micro-lamports). |
| `slippage` | decimal string | yes | 0 to 100 | Slippage tolerance in percent. `"15"` means 15%. |
| `bundle_amount` | decimal string | no | max length 32 | Bundle pressure in SOL for this channel. On Pump.fun, Pump AMM, LaunchLab, Meteora DBC and DAMM V2 the pool is advanced by this amount and no percentage slippage is added. An empty string (as in the spec example) leaves percentage slippage in effect. |
| `sol_slippage_mode` | boolean | no | | Per-channel SOL-slippage flag. The spec marks the shared flags as legacy and points to these per-mode flags as preferred. The spec does not define the SOL-slippage calculation itself. |

Practical reading of the rules: if you want plain percentage slippage, set `slippage` and leave `bundle_amount` empty. If you set a positive `bundle_amount` on a supported DEX, `slippage` stops being the limiting factor for that channel.

## DEX selection

| Field | Type | Required | Allowed values | Meaning |
|---|---|---|---|---|
| `selected_dexes` | array of strings | yes | 1 to 5 items from `pump-fun`, `launchlab`, `believe`, `bags`, `meteora-dynamic-bc` | DEXes (launch platforms) the sniper is allowed to act on. At least one entry is required even when `dex_source` is `global`. |
| `dex_source` | string enum | yes (default `global`) | `global`, `config` | Which list is authoritative. |

How the two fields interact:

| `dex_source` | Effective DEX list |
|---|---|
| `global` | The account's enabled global DEX list. `selected_dexes` is used only when the global list is unavailable. |
| `config` | Always `selected_dexes` from this config. |

Copy-trade configs accept a wider DEX set (including `pump-amm` and Raydium pools); the sniper enum is limited to the five values above.

## Creator (dev) buy filter

| Field | Type | Required | Limits | Meaning |
|---|---|---|---|---|
| `dev_min_amount` | decimal string | no | max length 32 | Lower bound on the creator's own buy amount. Empty string disables the lower bound. |
| `dev_max_amount` | decimal string | no | max length 32; must be >= `dev_min_amount` when both are set | Upper bound on the creator's own buy amount. Empty string disables the upper bound. |

The filter compares against the amount the token creator buys. The spec does not state the unit explicitly; the other amount fields in this config are in SOL. Both bounds empty (or omitted) means no creator-buy filtering.

## Behaviour switches

| Field | Type | Required | Default | Meaning |
|---|---|---|---|---|
| `buy_once` | boolean | yes | `false` | When `true`, the task deactivates itself after its first triggered trade. To snipe again, resume it (see [sniper](/xtrader/sniper/)). |
| `snipe_external` | boolean | yes | `false` | When `true`, the bonding curve is skipped and only supported external-pool execution is targeted. |
| `sol_slippage_mode` | boolean | yes | `false` | Legacy shared flag, listed above under execution channels. |

## Sell-side objects

All three are required in `config`. Their fields are documented on separate pages.

| 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 permanently). | [auto-sell](/xtrader/auto-sell/) |
| `auto_strategy` | Extra exit rules: clearing on migration, 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 orders. | [timed-strategy](/xtrader/timed-strategy/) |

The minimum shapes accepted by the schema are `auto_sell` with `enabled`, `expiry_time`, `tp_orders`, `sl_orders`, `follow_sell`, `proportional_sell`; `auto_strategy` with `migration_clear`, `timed_sell`, `sell_delay`; and `timed_strategy` with `enabled` and `orders`.

## What differs in SniperPatch

| Aspect | SniperCreate | SniperPatch |
|---|---|---|
| Top-level required fields | `remark`, `target_wallet`, `config` | None individually, but at least one top-level field must be sent |
| `target_wallet` | required | not accepted (immutable) |
| `remark` default | `""` | no default; omitted means unchanged |
| `config` | full object | when present, the full object again; it replaces the stored config and must satisfy the same schema |
| When allowed | always (creates paused) | `remark` and `risk_label_id` can change while active; `config` requires the task to be paused |
| Headers | `Idempotency-Key` | `If-Match` with the latest ETag, for example `"v3"` |

The nested `config` schema is identical in both: same required keys, same limits. There is no partial merge inside `config`. To change one value, GET the resource, modify the value in the returned config, and send the whole config back.

## Minimal valid create body

All required keys with sell-side features disabled and only percentage slippage:

```json
{
  "remark": "",
  "target_wallet": "11111111111111111111111111111111",
  "config": {
    "buy_amount": "0.1",
    "jito_mode": { "tip_amount": "0.01", "priority_fee": "0.0005", "slippage": "15" },
    "priority_mode": { "tip_amount": "0.001", "priority_fee": "0.005", "slippage": "15" },
    "selected_dexes": ["pump-fun"],
    "dex_source": "global",
    "buy_once": false,
    "sol_slippage_mode": false,
    "snipe_external": false,
    "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": [] }
  }
}
```

`11111111111111111111111111111111` is the placeholder address used in the spec examples; replace it with the creator wallet you want to snipe.

## Fuller example

Two DEXes, config-defined DEX list, creator buy filter, bundle pressure on the Jito channel, one-shot mode and a label:

```json
{
  "remark": "Pump + LaunchLab one-shot",
  "target_wallet": "11111111111111111111111111111111",
  "risk_label_id": "3f2c1a9e-8b7d-4c6e-9a1b-2d3e4f5a6b7c",
  "config": {
    "buy_amount": "0.25",
    "jito_mode": {
      "tip_amount": "0.01",
      "priority_fee": "0.0005",
      "slippage": "20",
      "bundle_amount": "0.5",
      "sol_slippage_mode": false
    },
    "priority_mode": {
      "tip_amount": "0.001",
      "priority_fee": "0.005",
      "slippage": "20",
      "bundle_amount": "",
      "sol_slippage_mode": false
    },
    "selected_dexes": ["pump-fun", "launchlab"],
    "dex_source": "config",
    "dev_min_amount": "0.5",
    "dev_max_amount": "5",
    "buy_once": true,
    "sol_slippage_mode": false,
    "snipe_external": false,
    "auto_sell": {
      "enabled": true,
      "tab": "tpsl",
      "expiry_time": "60",
      "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": [] }
  }
}
```

The `risk_label_id` must belong to a label in your own account. The `auto_sell` order fields (`trigger`, `sell`) are explained on the [auto-sell page](/xtrader/auto-sell/).

## Sending the body

```bash
curl --request POST 'https://x-trader.ai/api/v1/sniper/configs' \
  --header "Authorization: Bearer $X_TRADER_API_TOKEN" \
  --header 'Content-Type: application/json' \
  --header 'Idempotency-Key: create-sniper-20261016-001' \
  --data @sniper-config.json
```

```python
import json
import os

import requests

BASE = "https://x-trader.ai/api/v1"
headers = {
    "Authorization": f"Bearer {os.environ['X_TRADER_API_TOKEN']}",
    "Idempotency-Key": "create-sniper-20261016-001",
}

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

resp = requests.post(f"{BASE}/sniper/configs", json=body, headers=headers, timeout=30)
resp.raise_for_status()
created = resp.json()
etag = resp.headers.get("ETag")  # needed for later PATCH, pause, resume, delete
```

Changing `config` later (task must be paused, full config required):

```bash
curl --request PATCH "https://x-trader.ai/api/v1/sniper/configs/$CONFIG_ID" \
  --header "Authorization: Bearer $X_TRADER_API_TOKEN" \
  --header 'Content-Type: application/json' \
  --header 'If-Match: "v3"' \
  --data @sniper-config-updated.json
```

```python
config_id = os.environ["CONFIG_ID"]
current = requests.get(f"{BASE}/sniper/configs/{config_id}", headers={"Authorization": headers["Authorization"]}, timeout=30)
current.raise_for_status()
config = current.json()["data"]["config"]
config["buy_amount"] = "0.3"

resp = requests.patch(
    f"{BASE}/sniper/configs/{config_id}",
    json={"config": config},
    headers={"Authorization": headers["Authorization"], "If-Match": current.headers["ETag"]},
    timeout=30,
)
resp.raise_for_status()
```

Note that GET returns the stored snapshot as-is, and historical configs may include legacy web-UI fields that the strict schema now rejects. If a PATCH built from a GET result fails validation, remove keys that are not listed on this page.

## FAQ

### Which fields are required in a sniper config?

Inside `config`, `buy_amount`, `jito_mode`, `priority_mode`, `selected_dexes`, `dex_source`, `buy_once`, `sol_slippage_mode`, `snipe_external`, `auto_sell`, `auto_strategy` and `timed_strategy` are required. Only `bundle_amount`, `dev_min_amount` and `dev_max_amount` may be omitted.

### What is the difference between jito_mode and priority_mode?

Both objects carry the same fee and slippage fields. `jito_mode` holds the settings for Jito execution, `priority_mode` holds the settings for leader/direct execution. Both are required; the spec does not document how the channel for a given trade is chosen.

### Can I change only buy_amount with PATCH?

No. When `config` is present in a PATCH body it replaces the whole nested config and must pass the full schema, so send the complete object. The configuration must also be paused first.

### How do I disable the creator buy filter?

Send an empty string for `dev_min_amount` and `dev_max_amount`, or omit them. An empty string removes that bound.

### What does dex_source global mean?

With `global`, the task uses the account's enabled global DEX list and falls back to `selected_dexes` only when that list is unavailable. With `config`, `selected_dexes` is always used.
