Liquid

REST API

REST API Reference

Complete endpoint reference for the Liquid Trading API — authentication, market data, account, orders, positions, and errors.

Overview

Link

The Liquid Trading API provides authenticated access to market data, account state, order entry, and position management for perpetual futures markets.

PropertyValue
Base URLhttps://api.liquid.trade
Version/v1
AuthHMAC-SHA256 signed headers
FormatJSON request and response bodies
Rate limitsPer-key, per-second (see Rate Limits)

Authentication

Link

All endpoints except GET /v1/health require four HMAC authentication headers on every request.

HeaderDescription
X-Liquid-KeyYour API key (lq_...)
X-Liquid-TimestampCurrent unix timestamp in milliseconds
X-Liquid-NonceUnique per-request nonce (8-64 alphanumeric characters)
X-Liquid-SignatureHMAC-SHA256 hex signature of the canonical payload

The signing payload is a newline-delimited string:

signing payload
text
{timestamp_ms}
{nonce}
{METHOD}
{canonical_path}
{canonical_query}
{body_hash}

The signature is: hex(hmac_sha256(api_secret, payload))

Canonicalization rules

Method is uppercased. Path is lowercased with trailing slash stripped. Query params are sorted by key and percent-encoded. JSON bodies are serialized with sorted keys and compact separators before SHA-256 hashing.

Timestamp skew must be within 5,000ms. Nonces are single-use with a 15-second replay window.

example request
bash
curl https://api.liquid.trade/v1/account \
  -H "X-Liquid-Key: lq_..." \
  -H "X-Liquid-Timestamp: 1700000000000" \
  -H "X-Liquid-Nonce: abc123xyz789" \
  -H "X-Liquid-Signature: <hex-hmac>"
Use the SDK

The Python SDK handles signing automatically. You do not need to manually assemble HMAC headers unless building a custom client.

Permission Scopes

Link

API keys are assigned permission scopes that control which endpoints they can access.

ScopeValueAccess
READ1Market data, account info, order and position queries
TRADE2Place and cancel orders, close and modify positions

A key with value 3 has both READ and TRADE access. Most integrations should use a read+trade key.

Response Envelope

Link

Every response uses a consistent envelope:

success response
json
{
  "success": true,
  "data": { ... }
}
error response
json
{
  "success": false,
  "data": null,
  "error": {
    "code": "INSUFFICIENT_SCOPE",
    "message": "API key does not have trade permission"
  }
}

Rate Limits

Link
TierRequests/secOrder mutations/secMax keys
Free1023

Order mutation limits apply to POST /v1/orders, DELETE /v1/orders, and all position mutation routes. Rate limit state is returned in response headers:

HeaderDescription
X-RateLimit-LimitMaximum requests per second
X-RateLimit-RemainingRequests remaining in current window
X-RateLimit-ResetUnix timestamp when the window resets

When throttled, the API returns HTTP 429 with Retry-After: 1.

GET /v1/health

Link

Unauthenticated health check. Use this to verify connectivity.

request
bash
curl https://api.liquid.trade/v1/health
response
json
{
  "status": "ok",
  "version": "1.0.0"
}

GET /v1/markets

Link

List all tradeable symbols. Scope: READ.

request
bash
curl https://api.liquid.trade/v1/markets \
  -H "X-Liquid-Key: lq_..." \
  -H "X-Liquid-Timestamp: ..." \
  -H "X-Liquid-Nonce: ..." \
  -H "X-Liquid-Signature: ..."
response
json
{
  "success": true,
  "data": [
    {
      "symbol": "BTC-PERP",
      "ticker": "BTC",
      "exchange": "hyperliquid",
      "max_leverage": 40,
      "sz_decimals": 5
    },
    {
      "symbol": "ETH-PERP",
      "ticker": "ETH",
      "exchange": "hyperliquid",
      "max_leverage": 25,
      "sz_decimals": 4
    }
  ]
}
FieldTypeDescription
symbolstringLiquid symbol identifier (e.g. BTC-PERP)
tickerstringBase asset ticker
exchangestringUnderlying exchange
max_leverageintegerMaximum allowed leverage
sz_decimalsintegerSize decimal precision

GET /v1/markets/{symbol}/ticker

Link

Get current mark price and 24h metadata for a symbol. Scope: READ.

request
bash
curl https://api.liquid.trade/v1/markets/BTC-PERP/ticker \
  -H "X-Liquid-Key: lq_..." \
  -H "X-Liquid-Timestamp: ..." \
  -H "X-Liquid-Nonce: ..." \
  -H "X-Liquid-Signature: ..."
response
json
{
  "success": true,
  "data": {
    "symbol": "BTC-PERP",
    "mark_price": "69420.50",
    "volume_24h": "1234567.89",
    "change_24h": "2.34",
    "funding_rate": "0.0001"
  }
}
FieldTypeDescription
symbolstringSymbol identifier
mark_pricestringCurrent mark price
volume_24hstring24-hour trading volume in USD
change_24hstring24-hour price change percentage
funding_ratestringCurrent funding rate

GET /v1/markets/{symbol}/orderbook

Link

Get an L2 order book snapshot. Scope: READ.

Query ParamTypeDefaultDescription
depthinteger20Number of levels per side (1-500)
response
json
{
  "success": true,
  "data": {
    "symbol": "BTC-PERP",
    "bids": [
      { "price": "69400.00", "size": "1.25", "count": 3 }
    ],
    "asks": [
      { "price": "69420.00", "size": "0.80", "count": 2 }
    ],
    "timestamp": null
  }
}
Timestamp field

The orderbook timestamp is null in the current implementation. Use local request time if you need to track freshness.

GET /v1/markets/{symbol}/candles

Link

Get OHLCV candle data. Scope: READ.

Query ParamTypeDefaultDescription
intervalstring1h1m, 5m, 15m, 30m, 1h, 4h, 1d
limitinteger100Number of candles (1-1000)
startintegerStart unix timestamp in seconds (optional)
endintegerEnd unix timestamp in seconds (optional)
response
json
{
  "success": true,
  "data": [
    {
      "timestamp": 1700000000000,
      "open": "68000.0",
      "high": "68200.0",
      "low": "67850.0",
      "close": "68120.0",
      "volume": "1234.56"
    }
  ]
}

Account Endpoints

Link

All account endpoints require SCOPE_READ.

MethodEndpointDescription
GET/v1/accountMargin overview: equity, margin_used, available_balance, account_value
GET/v1/account/balancesDetailed breakdown including cross_margin (account_value, total_margin_used, total_ntl_pos)
GET/v1/account/positionsOpen positions: symbol, side, size, entry_price, mark_price, leverage, unrealized_pnl, liquidation_price, margin_used
GET /v1/account
json
{
  "success": true,
  "data": {
    "equity": "10523.45",
    "margin_used": "2100.00",
    "available_balance": "8423.45",
    "account_value": "10523.45"
  }
}
GET /v1/account/positions
json
{
  "success": true,
  "data": [
    {
      "symbol": "BTC-PERP",
      "side": "long",
      "size": "0.05",
      "entry_price": "69000.00",
      "mark_price": "69420.50",
      "leverage": 5,
      "unrealized_pnl": "21.00",
      "liquidation_price": "55200.00",
      "margin_used": "690.00"
    }
  ]
}

POST /v1/orders

Link

Place a market or limit order. Scope: TRADE.

FieldTypeRequiredDescription
symbolstringYesMarket symbol (e.g. BTC-PERP)
sidestringYesbuy or sell
typestringNomarket (default) or limit
sizenumberYesOrder size in USD notional (must be > 0)
pricenumberLimit onlyLimit price (required for limit orders)
leverageintegerNo1-200 (default 1)
time_in_forcestringNogtc (default) or ioc
tpnumberNoTake-profit trigger price
slnumberNoStop-loss trigger price
reduce_onlybooleanNoOnly reduce existing position
request body
json
{
  "symbol": "BTC-PERP",
  "side": "buy",
  "type": "market",
  "size": 100.0,
  "leverage": 5,
  "tp": 72000.0,
  "sl": 68000.0
}
response
json
{
  "success": true,
  "data": {
    "order_id": "ord_abc123",
    "symbol": "BTC-PERP",
    "side": "buy",
    "type": "market",
    "size": "100.0",
    "price": "69420.50",
    "leverage": 5,
    "status": "filled",
    "exchange": "hyperliquid",
    "tp": "72000.0",
    "sl": "68000.0",
    "reduce_only": false,
    "created_at": "2025-01-15T12:00:00Z"
  }
}
Size is USD notional

The size field is always in USD, not token count. For example, size: 100 with BTC at $69,000 buys roughly 0.00145 BTC.

Other Order Endpoints

Link
MethodEndpointScopeDescription
GET/v1/ordersREADList all open orders
GET/v1/orders/{order_id}READFetch a specific order (404 if not open)
DELETE/v1/ordersTRADECancel all open orders
DELETE/v1/orders/{order_id}TRADECancel a single order (404 if not open)
DELETE /v1/orders — partial failure (207)
json
{
  "success": false,
  "data": [
    { "order_id": "ord_abc123", "status": "cancelled" },
    { "order_id": "ord_def456", "status": "failed", "error": "Order not found" }
  ],
  "error": {
    "code": "PARTIAL_FAILURE",
    "message": "1 of 2 order cancellations failed; 1 succeeded."
  }
}
Cancel-all may return 207

DELETE /v1/orders returns 207 PARTIAL_FAILURE if some cancellations succeed and others fail. Always check individual statuses in the data array.

Position Endpoints

Link

All position endpoints require SCOPE_TRADE.

MethodEndpointDescription
POST/v1/positions/{symbol}/closeClose full position or partial close
PATCH/v1/positions/{symbol}/tp-slSet or update TP and/or SL
PATCH/v1/positions/{symbol}/marginAdjust isolated margin
PATCH/v1/positions/{symbol}/leverageUpdate leverage and margin mode
POST /v1/positions/BTC-PERP/close
json
// Omit size to close fully, or provide size in coin units for partial close
{
  "size": 0.025
}
PATCH /v1/positions/BTC-PERP/tp-sl
json
{
  "tp": 72000.0,
  "sl": 68000.0
}
PATCH /v1/positions/BTC-PERP/margin
json
{
  "amount": 500.0
}
PATCH /v1/positions/BTC-PERP/leverage
json
{
  "leverage": 10,
  "is_cross": false
}

Response examples:

POST /v1/positions/BTC-PERP/close response
json
{
  "success": true,
  "data": {
    "symbol": "BTC-PERP",
    "closed_size": 0.025,
    "status": "ok",
    "message": "Partial close executed"
  }
}
PATCH /v1/positions/BTC-PERP/tp-sl response
json
{
  "success": true,
  "data": {
    "tp": { "status": "set", "price": 72000.0 },
    "sl": { "status": "set", "price": 68000.0 }
  }
}
PATCH /v1/positions/BTC-PERP/leverage response
json
{
  "success": true,
  "data": {
    "symbol": "BTC-PERP",
    "leverage": 10,
    "is_cross": false
  }
}
PATCH /v1/positions/BTC-PERP/margin response
json
{
  "success": true,
  "data": {
    "symbol": "BTC-PERP",
    "margin_adjusted": 500.0
  }
}
Partial close uses coin units

When partially closing a position, the size field is in coin units (e.g. 0.025 BTC), not USD notional. Omit size to close the entire position.

Error Codes

Link
HTTPCodeDescription
400BAD_REQUESTInvalid request parameters
401MISSING_AUTH_HEADERSOne or more required HMAC headers were omitted
401INVALID_NONCENonce format invalid (must be 8-64 alphanumeric characters)
401INVALID_TIMESTAMPTimestamp format invalid or not a valid integer
401INVALID_API_KEYAPI key does not exist or is disabled
401INVALID_SIGNATURESignature mismatch — wrong secret or canonicalization error
401EXPIRED_TIMESTAMPRequest timestamp outside the 5-second skew window
401REPLAYED_NONCENonce was already used within the replay window
403INSUFFICIENT_SCOPEAPI key does not have the required permission scope
403IP_FORBIDDENRequest originated from a non-whitelisted IP address
404NOT_FOUNDResource does not exist (e.g. unknown order ID)
207PARTIAL_FAILURESome operations succeeded and some failed (e.g. cancel all orders)
422VALIDATION_ERRORInvalid request payload (missing fields, bad types)
429RATE_LIMIT_EXCEEDEDPer-second request or mutation rate exceeded
500INTERNAL_ERRORUnexpected server error
502EXCHANGE_ERRORUpstream exchange (Hyperliquid) returned an error
503AUTH_UNAVAILABLEAuth infrastructure temporarily unavailable
504TIMEOUTRequest timed out waiting for upstream response
error response example
json
{
  "success": false,
  "data": null,
  "error": {
    "code": "EXPIRED_TIMESTAMP",
    "message": "Request timestamp is outside the allowed 5000ms skew window"
  }
}