🛠️Integration Guides
1. Technical Flow & Diagrams
This is the end-to-end flow:
Login with SIWE → get JWT.
(Optional, but recommended) Create API key.
Enable Seamless Mode (Smart Trade) via EIP-712.
Ensure USD1 allowance is sufficient (
approveif not).Trade with Seamless Mode (open/close/update).
Read trading history & listen to WebSocket feeds.
1.1. High-level state flow

Interpretation:
NotLoggedIn
No JWT. App must execute SIWE login.
LoggedIn_NoSeamless
JWT exists, but Smart Trade (seamless) is not active.
Seamless_PendingAllowance
Smart Trade is active, but USD1 allowance to the trading contract is not yet sufficient.
→ App must check allowance and trigger
approvewhen needed.Seamless_ReadyToTrade
Smart Trade and USD1 allowance are both in place.
→ App can call trading APIs without extra signatures.
1.2. Detailed sequence diagram

2. Step-by-Step Guides
Swagger reference for all endpoints:
👉 perp-api.holdstation.com/docs
2.1. Login with SIWE → get JWT
Goal: Obtain a JWT bound to the user’s wallet.
Endpoints
POST /auth/noncePOST /auth/login
Summary
Call
POST /auth/noncewith:wallet,chain_id,domain,version.
Build a SIWE message from the response payload.
Ask the wallet to sign this SIWE message.
Send
POST /auth/loginwith:address,signature.
Store:
data.token(JWT),data.expired,data.wallet_address.
Use this JWT for all subsequent calls that require Bearer Auth.
2.2. Create & manage API keys (optional but recommended)
Some endpoints (e.g. pair info, histories) are protected by API Key in addition to JWT.
Endpoints
POST /apikey/apikey– create API keyGET /apikey/apikeys– list API keysDELETE /apikey/apikey– revoke API key
2.2.1. Create an API key
POST /apikey/apikeyHeaders:
Authorization: Bearer <token>Body:
{
"description": "string"
}Response
datacontains:apikey– the full secret key (show once, store securely),description,preview– short prefix for display,wallet_address– owner wallet.
Use this API key according to the API Key security scheme in Swagger
(e.g. header like x-api-key: <apikey>).
2.2.2. List API keys
GET /apikey/apikeysHeaders:
Authorization: Bearer <token>Query:
page(default 1),size(default 10).
Response data[] includes fields like created_at, description, key_hash, preview, wallet_address, etc.
2.2.3. Delete an API key
DELETE /apikey/apikeyHeaders:
Authorization: Bearer <token>Body:
{
"apikey": "the-key-to-revoke"
}Use this to revoke compromised or unused keys.
2.3. Enable Seamless Mode (Smart Trade)
Goal: Allow the Forwarder contract to trade on behalf of the user using JWT (no extra signatures per trade).
Endpoints
GET /smart-trade/saltGET /smart-trade/settingPOST /smart-tradeDELETE /smart-trade(to disable)
Checklist
GET /smart-trade/saltHeaders:
Authorization: Bearer <token>Response:
data.salt.
GET /smart-trade/settingHeaders:
Authorization: Bearer <token>Response:
data.forwarder(Forwarder contract address).
Ask wallet to sign EIP-712 typed data:
Domain:
{ name: 'Forwarder', version: '1', chainId: BigInt(chainId), verifyingContract: forwarderAddr }Types:
{ TradeRequest: [ { name: 'trader', type: 'address' }, { name: 'salt', type: 'bytes32' } ] }Value:
{ trader: wallet, salt: salt }
POST /smart-trade
{
"salt": "0x...",
"signature": "0x..."
}On success, optionally a new jwt and expired may be returned – update your stored token if present.
To disable Seamless Mode later, call DELETE /smart-trade with the same JWT.
2.4. Fetch pair info before trading
Goal: Get trading pairs & metadata (pair_index, symbol, leverage limits, etc.) so that you can:
Build your trading UI.
Resolve the correct
pair_indexand other parameters for/order/open,/order/close,/order/update.
Endpoint
GET /common/pair-info/{chainId}
Usage
Security:
Authorization: Bearer <token>API Key (per Swagger’s
API Keyscheme).
Path:
chainId– e.g.56for BSC.
The response data contains:
pairs[]– list of tradable pairs withpair_index, symbols, categories…groupsandcontracts– extra grouping / contract info.Other UI-level config.
You should cache this result per chain and refresh periodically.
2.5. Trade with Seamless Mode (including USD1 approve)
2.5.1. Prerequisites
Before calling any trade endpoint:
User is logged in (valid JWT).
Seamless Mode is enabled for that wallet (
/smart-tradedone).USD1 allowance for the trading contract is sufficient.
Allowance is not handled by the API – you should:
Trading contract: 0x8E2D60AC9238C46422005C8A8855d2ece37B3f86
Read it via standard ERC-20
allowance(trader, trading_contract)on-chain.If
< requiredAmount, ask the user to send anapprovetransaction:approve(trading_contract, amount).
Wait for confirmation before calling
/order/open.
2.5.2. Open trade
Endpoint
POST /order/open
Headers
Authorization: Bearer <token>
Body:
{
"$schema": "<https://example.com/schemas/OpenTradeRequestBody.json>",
"buy": true,
"leverage": 150,
"open_price": "910000000000000", // precision: 10
"order_type": 0, // 0: maarket, 1: limit, 2: stop
"pair_index": 0,
"position_size": "10000000000000000000", // the base usd1 amount to input, decimal 18
"sl": "920000000000000", // precision: 10
"tp": "890000000000000", // precision: 10
"trade_type": "market"
}
Key points:
pair_indexmust match one of the pairs from/common/pair-info/{chainId}.If the call returns non-200, treat as “trade failed” and show appropriate error.
2.5.3. Close trade
Endpoint
POST /order/close
Body (simplified):
{
"pair_index": 1,
"index": 0,
"trade_type": "market"
}
indexidentifies the user’s open position within that pair.Use open-position data (from WebSocket positions feed) to choose correct index.
2.5.4. Update SL/TP
Endpoint
POST /order/update
Body:
{
"pair_index": 1,
"index": 0,
"sl": "11000000000000", // precision: 10
"tp": "14000000000000" // precision: 10
}You can call this multiple times while the position is open.
2.6. Realtime price & order updates
2.6.1. Price WebSocket – realtime price feed
Use this channel to subscribe to live prices for pairs, phục vụ hiển thị chart / đặt lệnh:
URL:
wss://pricefeed.holdstation.com/v2Protocol: raw text over WebSocket
Message format (per line):
<pair_index>|<price>pair_index– numeric id of the trading pair (same as inpair-infoAPI).price– last traded / mark price for that pair, as string.
Example messages:
100|87451.94| 0|87439.12| 4|1.15222|Typical usage in frontend:
Fetch pairs via
GET /common/pair-info/{chainId}to knowpair_indexfor each symbol.Open WebSocket to
wss://pricefeed.holdstation.com/v2.Parse each incoming line, split by
"|"→ update local price store bypair_index.Use this price store for:
order ticket (mark/last price),
PnL / liquidation bar,
price alerts (nếu có).
2.6.2. SSE – real-time notifications for open orders
Use this channel to receive real-time notification for event open position
Endpoint:
GET /common/realtimeAuth:
Authorization: Bearer <JWT>(SIWE token), and/orx-api-key: <API key>(nếu bạn dùng API key layer).
Content-Type:
text/event-stream(Server Sent Events – SSE).
2.7. Trading history
Goal: Retrieve historical trades (open/close data, fees, PnL, …) to power your History screen or reconciliation.
Endpoint
GET /common/histories
Security
Authorization: Bearer <token>API Key
Query parameters (see Swagger for full list):
chain_idpagesize
Response data[] includes, for each trade, fields like:
created_on_chain_at,open_price,close_price,t_position_size_dai,collateral,leverage,open_fees,close_fees,funding_fees,rollover_fees,actual_pnl,actual_pnl_percentage, …
Use this to render history and/or to cross-check trades with your own storage.
2.8. Disabling Seamless Mode
When user wants to stop using keyless trading:
Call
DELETE /smart-tradewith the JWT.Consider:
Clearing UI flags (
seamlessEnabled = false).Optionally keeping JWT for non-seamless actions, or logging out completely depending on UX.
Last updated