Skip to content

X-Trader transfer-snipe API

A transfer-snipe task is a user-scoped X-Trader task that watches one wallet (the spec calls it watch wallet A, one per task) and carries a buy and sell strategy whose config schema is identical to the sniper config. It is managed through seven operations under /transfer-snipe/configs with the transfersnipe:read, transfersnipe:write and transfersnipe:delete scopes. Like sniper and copy-trade tasks, it is always created paused and runs only after POST /transfer-snipe/configs/{id}/resume.

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.

  • The tag description defines a transfer-snipe task as having one watch wallet A per task, with creation paused by design.
  • The only wallet field in the request body is target_wallet, so that field holds wallet A. It is a single Solana address and is immutable after creation.
  • TransferSnipeCreate states that its config shape matches sniper; the config schemas of SniperCreate and TransferSnipeCreate are the same.
  • Transfer-snipe tasks share the label set with sniper and copy-trade (LabelResource.transfer_snipe_count) and count toward the same configuration quota reported by GET /me.

The spec does not document which on-chain transfer events from wallet A trigger a buy, nor how the purchased token is chosen. It also defines no transfer-snipe templates.

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

Base URL https://x-trader.ai/api/v1. Error statuses listed for every operation: 400, 401, 403, 404, 409, 429, 500, 503. No bulk delete.

Header Where Rule
Authorization All Bearer xt_live_<id>.<secret>
Idempotency-Key Create 8-128 chars, A-Z a-z 0-9 . _ : -, retained 24 hours; reuse with another body gives idempotency_conflict
If-Match PATCH, DELETE, pause, resume Latest ETag, "v<number>"; stale gives version_conflict
ETag (response) 201/200 single-resource Send as If-Match next time
X-Request-Id (response) Single-resource and delete Support correlation

Shared write rules: /xtrader/write-rules/.

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

Ordering is by updated_at and id. Response: data.items, data.next_cursor, meta.request_id. See /xtrader/pagination/.

Top level (strict; user_id, version, template and unknown fields are rejected):

Field Type Required Default Constraint
remark string yes "" Max 64 characters, trimmed
target_wallet string yes Watch wallet A. Solana address, 32-44 characters, immutable
risk_label_id string (UUID) or null no Label owned by the account; null unassigns; foreign ID returns 404
config object yes Complete strategy, schema below

config (same schema as the sniper config; full reference at /xtrader/config-sniper/):

Field Type Required Default Constraint and meaning
buy_amount decimal string yes SOL per buy, greater than 0 and at most 1,000,000
jito_mode object yes Jito route fees: tip_amount (0-1,000 SOL), priority_fee (0-1,000 SOL), slippage (0-100 %) required; optional bundle_amount, sol_slippage_mode
priority_mode object yes Leader/direct route fees, same keys and ranges as jito_mode
bundle_amount decimal string no Legacy top-level fallback; prefer the copy inside jito_mode / priority_mode
selected_dexes array yes 1-5 of pump-fun, launchlab, believe, bags, meteora-dynamic-bc
dex_source string yes global global uses the enabled global DEX list (falls back to selected_dexes); config always uses selected_dexes
dev_min_amount decimal string no Lower bound of the creator buy filter; "" disables it
dev_max_amount decimal string no Upper bound; "" disables it; must be at least dev_min_amount when both are set
buy_once boolean yes false Deactivate the task after its first triggered trade
sol_slippage_mode boolean yes false Legacy shared SOL-slippage flag; per-mode flags take precedence
snipe_external boolean yes false Skip the bonding curve and use supported external-pool execution only
auto_sell object yes TP, SL, trailing TP, follow-sell; see /xtrader/auto-sell/
auto_strategy object yes Migration, timed sell, protections, sell-fee override; see /xtrader/auto-strategy/
timed_strategy object yes Up to 20 delayed sell orders; see /xtrader/timed-strategy/

All amounts, fees, percentages and durations are decimal strings (at most 12 fractional digits, max 32 characters), never JSON numbers. Every nested object is strict.

TransferSnipeResource adds the server fields id, is_active, version, created_at and updated_at, and returns remark, target_wallet, risk_label_id and config.

Terminal window
curl --request POST 'https://x-trader.ai/api/v1/transfer-snipe/configs' \
--header "Authorization: Bearer $X_TRADER_API_TOKEN" \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: create-transfer-20261016-001' \
--data '{
"remark": "Watch wallet A",
"target_wallet": "11111111111111111111111111111111",
"config": {
"buy_amount": "0.1",
"jito_mode": {"tip_amount": "0.01", "priority_fee": "0.0005", "slippage": "15", "bundle_amount": ""},
"priority_mode": {"tip_amount": "0.001", "priority_fee": "0.005", "slippage": "15", "bundle_amount": ""},
"selected_dexes": ["pump-fun"],
"dex_source": "global",
"dev_min_amount": "",
"dev_max_amount": "",
"buy_once": false,
"sol_slippage_mode": false,
"snipe_external": false,
"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": "c4e7a2b0-91d3-4f5e-a6b8-0d2c9e1f3a75",
"remark": "Watch wallet A",
"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",
"config": { "buy_amount": "0.1", "...": "stored config as sent" }
},
"meta": {
"request_id": "req_0123456789abcdef",
"persistence": "committed",
"propagation": "eventual"
}
}
  • GET /transfer-snipe/configs/{id}: missing and foreign IDs both return 404 not_found. The stored snapshot is returned as is, possibly with legacy fields.
  • PATCH /transfer-snipe/configs/{id} (TransferSnipePatch): at least one of remark, risk_label_id, config. While active, only remark and risk_label_id may change; pause before changing config. A config in the patch replaces the whole stored config and must pass the full schema. target_wallet cannot be patched. The operation text also mentions linked_wallets, but TransferSnipePatch has no such field and unknown fields are rejected.
  • DELETE /transfer-snipe/configs/{id}: only paused tasks; 204 on success.

Pause updates the stored state immediately; execution nodes pick it up eventually. Resume revalidates the complete stored config before activation and will not activate invalid historical data.

Terminal window
curl --request POST 'https://x-trader.ai/api/v1/transfer-snipe/configs/c4e7a2b0-91d3-4f5e-a6b8-0d2c9e1f3a75/resume' \
--header "Authorization: Bearer $X_TRADER_API_TOKEN" \
--header 'If-Match: "v1"'

Response 200 OK with the new ETag header (values illustrative):

{
"data": {
"id": "c4e7a2b0-91d3-4f5e-a6b8-0d2c9e1f3a75",
"remark": "Watch wallet A",
"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",
"config": { "buy_amount": "0.1", "...": "unchanged stored config" }
},
"meta": { "request_id": "req_0123456789abcdef", "persistence": "committed", "propagation": "eventual" }
}
import os
import requests
BASE = "https://x-trader.ai/api/v1"
H = {"Authorization": f"Bearer {os.environ['X_TRADER_API_TOKEN']}"}
tid = "c4e7a2b0-91d3-4f5e-a6b8-0d2c9e1f3a75"
r = requests.get(f"{BASE}/transfer-snipe/configs/{tid}", headers=H)
r.raise_for_status()
task, etag = r.json()["data"], r.headers["ETag"]
if task["is_active"]:
r = requests.post(f"{BASE}/transfer-snipe/configs/{tid}/pause", headers={**H, "If-Match": etag})
r.raise_for_status()
etag = r.headers["ETag"]
config = task["config"] # full object: PATCH replaces config completely
config["buy_amount"] = "0.2" # decimal string, not a number
r = requests.patch(f"{BASE}/transfer-snipe/configs/{tid}",
json={"config": config}, headers={**H, "If-Match": etag})
r.raise_for_status()
r = requests.post(f"{BASE}/transfer-snipe/configs/{tid}/resume",
headers={**H, "If-Match": r.headers["ETag"]})
r.raise_for_status()

If the stored snapshot contains legacy web-UI fields, the PATCH or resume can fail with validation_error; remove the fields listed in error.fields and send a config that matches the current schema.

  1. Create (paused) with an Idempotency-Key.
  2. Resume with the ETag from the create response.
  3. To change the strategy: pause, PATCH the full config, resume.
  4. remark and risk_label_id can change without pausing (still with If-Match).
  5. To remove: pause, then delete.

Error body: { "error": { "code", "message", "fields"? }, "request_id" }.

Code Typical cause on /transfer-snipe/configs
validation_error Unknown field, number instead of decimal string, empty PATCH, failed resume revalidation
insufficient_scope Token lacks the needed transfersnipe:* scope
not_found Unknown or foreign task ID, foreign label
config_must_be_paused config change or delete while active
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 with Retry-After

The spec does not say whether target_already_exists applies to transfer-snipe. Full list: /xtrader/errors/.

What is a transfer-snipe task in the X-Trader API?

Section titled “What is a transfer-snipe task in the X-Trader API?”

It is a user-scoped task with exactly one watch wallet (wallet A), stored in target_wallet, plus a strategy config whose shape matches the sniper config. Like other tasks it is created paused.

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

Can one transfer-snipe task watch several wallets?

Section titled “Can one transfer-snipe task watch several wallets?”

No. The spec defines one watch wallet A per task, and target_wallet is a single immutable address. Create one task per wallet.

Is the transfer-snipe config different from the sniper config?

Section titled “Is the transfer-snipe config different from the sniper config?”

No. The config object in TransferSnipeCreate and TransferSnipePatch has the same schema as the sniper config, including buy_amount, jito_mode, priority_mode and the sell objects.

The spec defines templates only for sniper and copy-trade. There are no /transfer-snipe/templates endpoints.