# X-Trader sniper and copy-trade templates API

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

X-Trader templates are reusable, named strategy snapshots owned by the current user: a template holds a `name` and a complete `config` in the same shape as a sniper or copy-trade task config. The API exposes them at `/sniper/templates` and `/copy-trade/templates` with list, create, get, patch and delete operations, guarded by the `sniper:*` and `copytrade:*` scopes respectively. Both kinds share a limit of 1,000 templates, and changing or deleting a template never rewrites the config stored in existing tasks.

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.

## Operations

| Method and path | Scope | Required headers | Success |
|---|---|---|---|
| `GET /sniper/templates` | `sniper:read` | `Authorization` | `200` list envelope |
| `POST /sniper/templates` | `sniper:write` | `Authorization`, `Idempotency-Key` | `201` resource envelope |
| `GET /sniper/templates/{id}` | `sniper:read` | `Authorization` | `200` resource envelope |
| `PATCH /sniper/templates/{id}` | `sniper:write` | `Authorization`, `If-Match` | `200` resource envelope |
| `DELETE /sniper/templates/{id}` | `sniper:delete` | `Authorization`, `If-Match` | `204` no body |
| `GET /copy-trade/templates` | `copytrade:read` | `Authorization` | `200` list envelope |
| `POST /copy-trade/templates` | `copytrade:write` | `Authorization`, `Idempotency-Key` | `201` resource envelope |
| `GET /copy-trade/templates/{id}` | `copytrade:read` | `Authorization` | `200` resource envelope |
| `PATCH /copy-trade/templates/{id}` | `copytrade:write` | `Authorization`, `If-Match` | `200` resource envelope |
| `DELETE /copy-trade/templates/{id}` | `copytrade:delete` | `Authorization`, `If-Match` | `204` no body |

Base URL `https://x-trader.ai/api/v1`. All operations also list `400`, `401`, `403`, `404`, `409`, `429`, `500` and `503`. There are no pause or resume operations for templates (a template does not execute), and there are no transfer-snipe templates.

## Headers

| Header | Where | Rule |
|---|---|---|
| `Authorization` | All | `Bearer xt_live_<id>.<secret>` |
| `Idempotency-Key` | POST create | 8-128 chars from `A-Z a-z 0-9 . _ : -`, retained 24 hours; same key with another body gives `idempotency_conflict` |
| `If-Match` | PATCH, DELETE | Latest `ETag` such as `"v3"`; stale gives `version_conflict` |
| `ETag` (response) | 201/200 single-template responses | Version for the next write |
| `X-Request-Id` (response) | Single-template and delete responses | Support correlation |

## Fields

### Create body (`SniperTemplateCreate`, `CopyTradeTemplateCreate`)

| Field | Type | Required | Rule |
|---|---|---|---|
| `name` | string | yes | 1-64 characters, leading and trailing spaces removed |
| `config` | object | yes | Complete strategy object. Sniper templates use the sniper config schema ([/xtrader/config-sniper/](/xtrader/config-sniper/)); copy-trade templates use the copy-trade config schema ([/xtrader/config-copy-trade/](/xtrader/config-copy-trade/)). |

Rejected on create: `user_id`, `version`, `risk_label_id`, and any unknown property. Templates never accept or return `risk_label_id`, so labels apply to tasks only (see [/xtrader/labels/](/xtrader/labels/)). Task-level fields such as `remark`, `target_wallet` and `linked_wallets` are not part of the template schemas.

### Patch body (`SniperTemplatePatch`, `CopyTradeTemplatePatch`)

At least one of `name` and `config`. `config`, when present, is a complete replacement that must pass the full schema; it is not merged into the stored config.

### Resource (`SniperTemplateResource`, `CopyTradeTemplateResource`)

| Field | Type | Meaning |
|---|---|---|
| `id` | UUID | Server-generated template ID |
| `name` | string | Display name |
| `version` | integer | Concurrency version, also returned as `ETag` |
| `created_at` | string | ISO 8601 with UTC offset |
| `updated_at` | string | ISO 8601 with UTC offset |
| `config` | object | Stored strategy snapshot |

## List

`GET /sniper/templates` and `GET /copy-trade/templates` return only the caller's templates.

| Query parameter | Type | Rule |
|---|---|---|
| `limit` | integer | 1-100, default 20 |
| `cursor` | string | Max 2048; opaque `next_cursor`, bound to the token and the search query |
| `q` | string | Max 64; searches template names only |

There are no `status` or `label_id` filters on template lists. Response: `data.items`, `data.next_cursor` (string or null), `meta.request_id`. See [/xtrader/pagination/](/xtrader/pagination/).

## Create

```bash
curl --request POST 'https://x-trader.ai/api/v1/sniper/templates' \
  --header "Authorization: Bearer $X_TRADER_API_TOKEN" \
  --header 'Content-Type: application/json' \
  --header 'Idempotency-Key: template-create-001' \
  --data '{
    "name": "Pump launch defaults",
    "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`, `X-Request-Id`; IDs and timestamps illustrative):

```json
{
  "data": {
    "id": "5b9d3e1a-2c7f-4a8b-9e6d-4f1a0c3b7d92",
    "name": "Pump launch defaults",
    "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" }
}
```

A copy-trade template is created the same way at `/copy-trade/templates`, with a copy-trade `config` (starting with `buy_config_mode`, `buy_config_universal`, `buy_config_tiers` and so on).

## Patch semantics

`PATCH /{kind}/templates/{id}` can rename the template, replace its full config, or both. The spec states explicitly that existing tasks are not rewritten automatically: a task keeps the config snapshot it was created or last patched with. To roll a template change out to tasks, pause each task, PATCH its `config` with the new template config, and resume it.

```bash
curl --request PATCH 'https://x-trader.ai/api/v1/sniper/templates/5b9d3e1a-2c7f-4a8b-9e6d-4f1a0c3b7d92' \
  --header "Authorization: Bearer $X_TRADER_API_TOKEN" \
  --header 'Content-Type: application/json' \
  --header 'If-Match: "v1"' \
  --data '{"name": "Updated defaults"}'
```

## Delete semantics

`DELETE /{kind}/templates/{id}` removes the template and detaches linked tasks (the link is cleared with `ON DELETE SET NULL`). Tasks are not deleted, and their stored config snapshots are not changed. Templates need no pause before delete. Success is `204` with no body.

## Name conflicts and the 1,000 limit

- `template_name_exists` is the error code for a name clash. The spec does not state the uniqueness scope (per kind or across both kinds); treat names as unique per account and pick a different `name` or rename the existing template.
- Sniper and copy-trade templates share one limit of 1,000 templates in total. The spec does not name the error code returned at the limit; `quota_exceeded` is the only quota code in the error enum.
- Templates are separate from the task configuration quota reported by `GET /me`, which covers sniper, copy-trade and transfer-snipe tasks.

## How a task relates to a template

The spec mentions linked tasks (delete detaches them) but the public API exposes no field to set or read that link: `SniperCreate` and `CopyTradeCreate` explicitly reject a `template` property, and task resources return no template ID. Through the API, a template therefore works as a copy source:

```python
import os
import uuid
import requests

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

tpl = requests.get(f"{BASE}/copy-trade/templates/5b9d3e1a-2c7f-4a8b-9e6d-4f1a0c3b7d92", headers=H)
tpl.raise_for_status()
config = tpl.json()["data"]["config"]

task = requests.post(
    f"{BASE}/copy-trade/configs",
    json={
        "remark": "From template",
        "target_wallet": "11111111111111111111111111111111",
        "linked_wallets": [],
        "config": config,
    },
    headers={**H, "Idempotency-Key": f"copy-{uuid.uuid4()}"},
)
task.raise_for_status()
print(task.json()["data"]["id"], task.headers["ETag"])  # created paused
```

Because template list and get return the stored snapshot as is, an older template may contain legacy fields that the current task schema rejects; in that case the create fails with `validation_error` and `error.fields` points to the offending paths. Task endpoints: [/xtrader/sniper/](/xtrader/sniper/), [/xtrader/copy-trade/](/xtrader/copy-trade/).

## Errors

| Code | Typical cause on template endpoints |
|---|---|
| `validation_error` | Empty or too long `name`, unknown field, `risk_label_id` in body, config not matching the schema, empty PATCH |
| `template_name_exists` | Name already used |
| `quota_exceeded` | Likely code at the shared 1,000-template limit (not stated in the spec) |
| `insufficient_scope` | Missing `sniper:*` or `copytrade:*` scope for the operation |
| `not_found` | Unknown template ID or one owned by another user |
| `version_conflict` | Stale `If-Match` on PATCH or DELETE |
| `idempotency_required` / `idempotency_conflict` | Missing key on create, or key reused with another body |
| `rate_limit_exceeded`, `service_unavailable` | `429` / `503` with `Retry-After` |

Error body shape and handling: [/xtrader/errors/](/xtrader/errors/).

## FAQ

### Does updating a template change tasks created from it?

No. A template PATCH replaces the template's own `name` or `config` only; existing task config snapshots are not rewritten.

### What happens to tasks when I delete a template?

Linked tasks are detached from the template, not deleted, and their stored config snapshots stay as they were.

### How many templates can an account have?

Sniper and copy-trade templates share one limit of 1,000 templates in total.

### How do I create a task from a template through the API?

The public task schemas have no template reference field and reject a `template` property. GET the template, copy its `config` into the task create body, and POST it as a normal sniper or copy-trade create.

### Which scopes do templates need?

Sniper templates use `sniper:read`, `sniper:write` and `sniper:delete`. Copy-trade templates use `copytrade:read`, `copytrade:write` and `copytrade:delete`.
