X-Trader API cursor pagination
X-Trader Public API list endpoints use opaque cursor pagination: each response returns data.items and data.next_cursor, and the next page is requested by passing next_cursor unchanged as the cursor query parameter. Pages contain 20 items by default and at most 100 (limit). A null next_cursor marks the last page, and a cursor is valid only for the same token and the same filters.
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.
Paginated endpoints
Section titled “Paginated endpoints”| Endpoint | Scope | Order |
|---|---|---|
GET /sniper/configs |
sniper:read |
updated_at, then id |
GET /copy-trade/configs |
copytrade:read |
updated_at, then id |
GET /transfer-snipe/configs |
transfersnipe:read |
updated_at, then id |
GET /sniper/templates |
sniper:read |
not stated in the spec |
GET /copy-trade/templates |
copytrade:read |
not stated in the spec |
GET /labels is not paginated (see below). The spec states that config lists are ordered by updated_at and id for stable paging but does not state the direction (ascending or descending).
Query parameters
Section titled “Query parameters”Config lists (sniper, copy-trade, transfer-snipe)
Section titled “Config lists (sniper, copy-trade, transfer-snipe)”| Parameter | Type | Default | Constraints | Meaning |
|---|---|---|---|---|
limit |
integer | 20 | 1-100 | Items per page |
cursor |
string | none | max 2048 characters | Opaque signed cursor from the previous page |
status |
enum | none | active, paused |
Filter by execution state (is_active) |
q |
string | none | max 64 characters | Search in remark and target_wallet, own resources only |
label_id |
string | none | label UUID or literal unlabeled |
Only tasks with this label, or with no label |
A label_id UUID that is missing or owned by another account returns 404 not_found.
Template lists (sniper, copy-trade)
Section titled “Template lists (sniper, copy-trade)”| Parameter | Type | Default | Constraints | Meaning |
|---|---|---|---|---|
limit |
integer | 20 | 1-100 | Items per page |
cursor |
string | none | max 2048 characters | Opaque signed cursor, bound to the token and the search query |
q |
string | none | max 64 characters | Search template names only |
Template lists have no status or label_id filter (templates never carry a label).
Response shape
Section titled “Response shape”{ "data": { "items": [ { "id": "...", "version": 3, "is_active": false } ], "next_cursor": "opaque-string-or-null" }, "meta": { "request_id": "req_0123456789abcdef" }}| Field | Type | Meaning |
|---|---|---|
data.items |
array | Resources of the page, in the same shape as single GET results |
data.next_cursor |
string or null (required) |
Cursor for the next page; null when there are no more pages |
meta.request_id |
string | Request identifier |
Items are returned as stored snapshots and may contain legacy fields (see write rules). List responses do not carry per-item ETag headers; use each item’s version or a single GET before writing.
Cursor rules
Section titled “Cursor rules”- Treat the cursor as opaque: pass it unchanged, never parse, decode or edit it.
- It is bound to the token that produced it. A cursor from one token is not usable with another (including a rotated token, as practical guidance).
- It is bound to the filters (
status,q,label_idon config lists;qon template lists). After changing any filter, restart from the first page withoutcursor. - Keep
limitand filters identical across pages of one traversal. - The spec does not document cursor expiry or the error code for an invalid cursor. As practical guidance, on a
400error for a cursor request restart from the first page.
Examples
Section titled “Examples”First page of paused sniper configs, 50 per page:
curl 'https://x-trader.ai/api/v1/sniper/configs?limit=50&status=paused' \ --header "Authorization: Bearer $X_TRADER_API_TOKEN"Next page (the cursor must be URL-encoded):
curl --get 'https://x-trader.ai/api/v1/sniper/configs' \ --header "Authorization: Bearer $X_TRADER_API_TOKEN" \ --data-urlencode 'limit=50' \ --data-urlencode 'status=paused' \ --data-urlencode "cursor=$NEXT_CURSOR"Python loop fetching every page:
import osimport requests
BASE = "https://x-trader.ai/api/v1"H = {"Authorization": f"Bearer {os.environ['X_TRADER_API_TOKEN']}"}
def fetch_all(path, **filters): params = {"limit": 100, **filters} items = [] while True: r = requests.get(f"{BASE}{path}", headers=H, params=params, timeout=15) r.raise_for_status() data = r.json()["data"] items.extend(data["items"]) cursor = data["next_cursor"] if cursor is None: return items params = {**params, "cursor": cursor} # same limit and filters, new cursor
active_copy = fetch_all("/copy-trade/configs", status="active")unlabeled_snipers = fetch_all("/sniper/configs", label_id="unlabeled")templates = fetch_all("/sniper/templates", q="night")print(len(active_copy), len(unlabeled_snipers), len(templates))requests URL-encodes params, so the cursor is passed through unchanged.
Labels list
Section titled “Labels list”GET /labels takes no query parameters and returns every label of the account in data.items, with no next_cursor. There are at most 20 labels, ordered by sort_order, then created_at. See labels.
How many items does an X-Trader list return?
Section titled “How many items does an X-Trader list return?”20 by default. Set limit to any integer from 1 to 100.
How do I know I reached the last page?
Section titled “How do I know I reached the last page?”data.next_cursor is null. Otherwise pass it unchanged as the cursor query parameter on the next request.
Can I change filters while paging?
Section titled “Can I change filters while paging?”No. Cursors are bound to the token and the filters of the first request. After changing status, q or label_id, restart from the first page without a cursor.
Is the labels list paginated?
Section titled “Is the labels list paginated?”No. GET /labels takes no parameters and returns all labels (at most 20) in data.items without next_cursor.