Getting Started
Quick start guide for integrating with the Synthetix Trading API.
Prerequisites
- Ethereum wallet with private key
- Node.js 18+ or Python 3.8+
- Basic understanding of EIP-712 signatures
- Funded account via the app (currently for select users only)
For API endpoints and connection details, see Environments.
Order Types
The Synthetix API uses a flat structure for order types:
| Order Type | Description | Required Fields | Example |
|---|---|---|---|
market | Market order | - | {orderType: "market"} |
limitGtc | Limit Good Till Canceled | price | {orderType: "limitGtc", price: "50000"} |
limitIoc | Limit Immediate or Cancel | price | {orderType: "limitIoc", price: "50000"} |
limitAlo | Limit Add Liquidity Only (Post-only) | price | {orderType: "limitAlo", price: "50000"} |
triggerSl | Trigger Stop Loss | triggerPrice | {orderType: "triggerSl", triggerPrice: "45000", isTriggerMarket: true} |
triggerTp | Trigger Take Profit | triggerPrice | {orderType: "triggerTp", triggerPrice: "55000", isTriggerMarket: true} |
Order Structure
{
symbol: "BTC-USDT",
side: "buy" | "sell",
quantity: "0.01",
orderType: "limitGtc", // Flat enum value
price: "50000", // Required for limit orders, empty string for market
triggerPrice: "", // Required for trigger orders, empty string otherwise
isTriggerMarket: false, // true for market execution on trigger
reduceOnly: false // Position reduction only
}Field Requirements by Order Type
| Order Type | price | triggerPrice | isTriggerMarket | Notes |
|---|---|---|---|---|
market | "" (empty) | "" (empty) | false | Executes immediately at market price |
limitGtc | Required | "" (empty) | false | Limit order, good till canceled |
limitIoc | Required | "" (empty) | false | Immediate or cancel |
limitAlo | Required | "" (empty) | false | Post-only (maker only) |
triggerSl | "" or price | Required | true/false | Stop loss: true = market, false = limit |
triggerTp | "" or price | Required | true/false | Take profit: true = market, false = limit |
Quick Start Example
JavaScript/TypeScript
npm install ethers axiosconst { ethers } = require('ethers');
const axios = require('axios');
const PRIVATE_KEY = process.env.PRIVATE_KEY;
class SynthetixClient {
constructor(privateKey) {
this.wallet = new ethers.Wallet(privateKey);
// EIP-712 domain
this.domain = {
name: "Synthetix",
version: "1",
chainId: 1,
verifyingContract: "0x0000000000000000000000000000000000000000"
};
// API base URL
this.apiBaseUrl = 'https://papi.synthetix.io';
}
getNonce() {
return Date.now();
}
// Get subaccount IDs for a wallet (public endpoint, no auth)
async getSubAccountIds(walletAddress) {
const response = await axios.post(`${this.apiBaseUrl}/v1/info`, {
params: {
action: 'getSubAccountIds',
walletAddress: walletAddress
}
});
return response.data.response;
}
// Place orders
async placeOrders(subAccountId, orders) {
const types = {
PlaceOrders: [
{ name: "orders", type: "Order[]" },
{ name: "nonce", type: "uint256" },
{ name: "expiresAfter", type: "uint256" }
],
Order: [
{ name: "symbol", type: "string" },
{ name: "side", type: "string" },
{ name: "quantity", type: "string" },
{ name: "orderType", type: "string" },
{ name: "price", type: "string" },
{ name: "triggerPrice", type: "string" },
{ name: "isTriggerMarket", type: "bool" },
{ name: "reduceOnly", type: "bool" }
]
};
const message = {
orders: orders,
nonce: this.getNonce(),
expiresAfter: 0
};
const signature = await this.wallet.signTypedData(this.domain, types, message);
const { v, r, s } = ethers.Signature.from(signature);
const response = await axios.post(`${this.apiBaseUrl}/v1/trade`, {
params: { action: "placeOrders", orders },
subAccountId,
nonce: message.nonce,
signature: { v, r, s }
});
return response.data.response;
}
}
// Usage
async function main() {
const client = new SynthetixClient(PRIVATE_KEY);
// Get subaccount IDs and use the master (first) subaccount
const subAccountIds = await client.getSubAccountIds(client.wallet.address);
if (subAccountIds.length === 0) {
throw new Error('No subaccounts found. Please fund your account via the app first.');
}
const subAccountId = subAccountIds[0]; // Use master subaccount
console.log(`Using subaccount: ${subAccountId}`);
// Place a limit order
const result = await client.placeOrders(subAccountId, [{
symbol: "BTC-USDT",
side: "buy",
orderType: "limitGtc",
quantity: "0.01",
price: "50000.00",
triggerPrice: "",
isTriggerMarket: false,
reduceOnly: false
}]);
console.log('Order placed:', result);
}
main().catch(console.error);Python
pip install eth-account requestsimport os
import time
from eth_account import Account
from eth_account.messages import encode_structured_data
import requests
class SynthetixClient:
def __init__(self, private_key):
self.account = Account.from_key(private_key)
# API base URL
self.api_base_url = "https://papi.synthetix.io"
# EIP-712 domain - chainId matches the blockchain network
self.domain = {
"name": "Synthetix",
"version": "1",
"chainId": 1,
"verifyingContract": "0x0000000000000000000000000000000000000000"
}
def get_nonce(self):
return int(time.time() * 1000)
def sign_typed_data(self, primary_type, types, message):
typed_data = {
"types": {
"EIP712Domain": [
{"name": "name", "type": "string"},
{"name": "version", "type": "string"},
{"name": "chainId", "type": "uint256"},
{"name": "verifyingContract", "type": "address"}
],
**types
},
"primaryType": primary_type,
"domain": self.domain,
"message": message
}
encoded = encode_structured_data(typed_data)
signed = self.account.sign_message(encoded)
return {"v": signed.v, "r": hex(signed.r), "s": hex(signed.s)}
def get_subaccount_ids(self, wallet_address):
response = requests.post(
f"{self.api_base_url}/v1/info",
json={"params": {"action": "getSubAccountIds", "walletAddress": wallet_address}}
)
return response.json()["response"]
def place_orders(self, sub_account_id, orders):
nonce = self.get_nonce()
types = {
"PlaceOrders": [
{"name": "orders", "type": "Order[]"},
{"name": "nonce", "type": "uint256"},
{"name": "expiresAfter", "type": "uint256"}
],
"Order": [
{"name": "symbol", "type": "string"},
{"name": "side", "type": "string"},
{"name": "quantity", "type": "string"},
{"name": "orderType", "type": "string"},
{"name": "price", "type": "string"},
{"name": "triggerPrice", "type": "string"},
{"name": "isTriggerMarket", "type": "bool"},
{"name": "reduceOnly", "type": "bool"}
]
}
message = {"orders": orders, "nonce": nonce, "expiresAfter": 0}
signature = self.sign_typed_data("PlaceOrders", types, message)
response = requests.post(
f"{self.api_base_url}/v1/trade",
json={"params": {"action": "placeOrders", "orders": orders}, "subAccountId": str(sub_account_id), "nonce": nonce, "signature": signature}
)
return response.json()["response"]
# Usage
client = SynthetixClient(os.getenv("PRIVATE_KEY"))
# Get subaccount IDs and use the master (first) subaccount
subaccount_ids = client.get_subaccount_ids(client.account.address)
if not subaccount_ids:
raise Exception("No subaccounts found. Please fund your account via the app first.")
sub_account_id = subaccount_ids[0] # Use master subaccount
print(f"Using subaccount: {sub_account_id}")
# Place order
result = client.place_orders(sub_account_id, [{
"symbol": "BTC-USDT",
"side": "buy",
"orderType": "limitGtc",
"quantity": "0.01",
"price": "50000.00",
"triggerPrice": "",
"isTriggerMarket": False,
"reduceOnly": False
}])
print("Order placed:", result)Additional Order Examples
// Market order
{ orderType: "market", price: "", triggerPrice: "" }
// Limit IOC (Immediate or Cancel)
{ orderType: "limitIoc", price: "50000.00", triggerPrice: "" }
// Limit ALO (Add Liquidity Only / Post-only)
{ orderType: "limitAlo", price: "50000.00", triggerPrice: "" }
// Stop Loss (market execution on trigger)
{ orderType: "triggerSl", price: "", triggerPrice: "45000.00", isTriggerMarket: true }
// Take Profit (limit execution on trigger)
{ orderType: "triggerTp", price: "55000.00", triggerPrice: "54000.00", isTriggerMarket: false }WebSocket Real-Time Updates
For real-time order updates and market data streaming, see the WebSocket API documentation.
Available subscriptions:
- Order updates - Real-time fills, cancellations, rejections
- Market prices - Live price feeds
- Orderbook - Depth updates
- Trades - Public trade execution events
Next Steps
- REST API Reference - Complete endpoint documentation
- WebSocket Guide - Real-time data streaming
- Environments - Environment configuration
- Authentication - EIP-712 signing details