Place order
curl --request POST \
--url https://api.hyperliquid.xyz/exchange \
--header 'Content-Type: application/json' \
--data '
{
"action": {
"type": "order",
"orders": [
{
"a": 0,
"b": true,
"p": "50000.0",
"s": "0.01",
"r": false,
"t": {
"limit": {
"tif": "Gtc"
}
}
}
],
"grouping": "na"
},
"nonce": 1705234567890,
"signature": {
"r": "0x0000000000000000000000000000000000000000000000000000000000000000",
"s": "0x0000000000000000000000000000000000000000000000000000000000000000",
"v": 27
},
"vaultAddress": null
}
'import requests
url = "https://api.hyperliquid.xyz/exchange"
payload = {
"action": {
"type": "order",
"orders": [
{
"a": 0,
"b": True,
"p": "50000.0",
"s": "0.01",
"r": False,
"t": { "limit": { "tif": "Gtc" } }
}
],
"grouping": "na"
},
"nonce": 1705234567890,
"signature": {
"r": "0x0000000000000000000000000000000000000000000000000000000000000000",
"s": "0x0000000000000000000000000000000000000000000000000000000000000000",
"v": 27
},
"vaultAddress": None
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
action: {
type: 'order',
orders: [{a: 0, b: true, p: '50000.0', s: '0.01', r: false, t: {limit: {tif: 'Gtc'}}}],
grouping: 'na'
},
nonce: 1705234567890,
signature: {
r: '0x0000000000000000000000000000000000000000000000000000000000000000',
s: '0x0000000000000000000000000000000000000000000000000000000000000000',
v: 27
},
vaultAddress: null
})
};
fetch('https://api.hyperliquid.xyz/exchange', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.hyperliquid.xyz/exchange",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'action' => [
'type' => 'order',
'orders' => [
[
'a' => 0,
'b' => true,
'p' => '50000.0',
's' => '0.01',
'r' => false,
't' => [
'limit' => [
'tif' => 'Gtc'
]
]
]
],
'grouping' => 'na'
],
'nonce' => 1705234567890,
'signature' => [
'r' => '0x0000000000000000000000000000000000000000000000000000000000000000',
's' => '0x0000000000000000000000000000000000000000000000000000000000000000',
'v' => 27
],
'vaultAddress' => null
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.hyperliquid.xyz/exchange"
payload := strings.NewReader("{\n \"action\": {\n \"type\": \"order\",\n \"orders\": [\n {\n \"a\": 0,\n \"b\": true,\n \"p\": \"50000.0\",\n \"s\": \"0.01\",\n \"r\": false,\n \"t\": {\n \"limit\": {\n \"tif\": \"Gtc\"\n }\n }\n }\n ],\n \"grouping\": \"na\"\n },\n \"nonce\": 1705234567890,\n \"signature\": {\n \"r\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n \"s\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n \"v\": 27\n },\n \"vaultAddress\": null\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.hyperliquid.xyz/exchange")
.header("Content-Type", "application/json")
.body("{\n \"action\": {\n \"type\": \"order\",\n \"orders\": [\n {\n \"a\": 0,\n \"b\": true,\n \"p\": \"50000.0\",\n \"s\": \"0.01\",\n \"r\": false,\n \"t\": {\n \"limit\": {\n \"tif\": \"Gtc\"\n }\n }\n }\n ],\n \"grouping\": \"na\"\n },\n \"nonce\": 1705234567890,\n \"signature\": {\n \"r\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n \"s\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n \"v\": 27\n },\n \"vaultAddress\": null\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.hyperliquid.xyz/exchange")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"action\": {\n \"type\": \"order\",\n \"orders\": [\n {\n \"a\": 0,\n \"b\": true,\n \"p\": \"50000.0\",\n \"s\": \"0.01\",\n \"r\": false,\n \"t\": {\n \"limit\": {\n \"tif\": \"Gtc\"\n }\n }\n }\n ],\n \"grouping\": \"na\"\n },\n \"nonce\": 1705234567890,\n \"signature\": {\n \"r\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n \"s\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n \"v\": 27\n },\n \"vaultAddress\": null\n}"
response = http.request(request)
puts response.read_body{
"status": "ok",
"response": {
"type": "order",
"data": {
"statuses": [
{
"resting": {
"oid": 77738308
}
}
]
}
}
}Hyperliquid node API
Place order | Hyperliquid exchange
Places one or multiple orders on the Hyperliquid exchange. Supports limit orders, market orders, and trigger orders (stop-loss/take-profit).
POST
/
exchange
Place order
curl --request POST \
--url https://api.hyperliquid.xyz/exchange \
--header 'Content-Type: application/json' \
--data '
{
"action": {
"type": "order",
"orders": [
{
"a": 0,
"b": true,
"p": "50000.0",
"s": "0.01",
"r": false,
"t": {
"limit": {
"tif": "Gtc"
}
}
}
],
"grouping": "na"
},
"nonce": 1705234567890,
"signature": {
"r": "0x0000000000000000000000000000000000000000000000000000000000000000",
"s": "0x0000000000000000000000000000000000000000000000000000000000000000",
"v": 27
},
"vaultAddress": null
}
'import requests
url = "https://api.hyperliquid.xyz/exchange"
payload = {
"action": {
"type": "order",
"orders": [
{
"a": 0,
"b": True,
"p": "50000.0",
"s": "0.01",
"r": False,
"t": { "limit": { "tif": "Gtc" } }
}
],
"grouping": "na"
},
"nonce": 1705234567890,
"signature": {
"r": "0x0000000000000000000000000000000000000000000000000000000000000000",
"s": "0x0000000000000000000000000000000000000000000000000000000000000000",
"v": 27
},
"vaultAddress": None
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
action: {
type: 'order',
orders: [{a: 0, b: true, p: '50000.0', s: '0.01', r: false, t: {limit: {tif: 'Gtc'}}}],
grouping: 'na'
},
nonce: 1705234567890,
signature: {
r: '0x0000000000000000000000000000000000000000000000000000000000000000',
s: '0x0000000000000000000000000000000000000000000000000000000000000000',
v: 27
},
vaultAddress: null
})
};
fetch('https://api.hyperliquid.xyz/exchange', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.hyperliquid.xyz/exchange",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'action' => [
'type' => 'order',
'orders' => [
[
'a' => 0,
'b' => true,
'p' => '50000.0',
's' => '0.01',
'r' => false,
't' => [
'limit' => [
'tif' => 'Gtc'
]
]
]
],
'grouping' => 'na'
],
'nonce' => 1705234567890,
'signature' => [
'r' => '0x0000000000000000000000000000000000000000000000000000000000000000',
's' => '0x0000000000000000000000000000000000000000000000000000000000000000',
'v' => 27
],
'vaultAddress' => null
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.hyperliquid.xyz/exchange"
payload := strings.NewReader("{\n \"action\": {\n \"type\": \"order\",\n \"orders\": [\n {\n \"a\": 0,\n \"b\": true,\n \"p\": \"50000.0\",\n \"s\": \"0.01\",\n \"r\": false,\n \"t\": {\n \"limit\": {\n \"tif\": \"Gtc\"\n }\n }\n }\n ],\n \"grouping\": \"na\"\n },\n \"nonce\": 1705234567890,\n \"signature\": {\n \"r\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n \"s\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n \"v\": 27\n },\n \"vaultAddress\": null\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.hyperliquid.xyz/exchange")
.header("Content-Type", "application/json")
.body("{\n \"action\": {\n \"type\": \"order\",\n \"orders\": [\n {\n \"a\": 0,\n \"b\": true,\n \"p\": \"50000.0\",\n \"s\": \"0.01\",\n \"r\": false,\n \"t\": {\n \"limit\": {\n \"tif\": \"Gtc\"\n }\n }\n }\n ],\n \"grouping\": \"na\"\n },\n \"nonce\": 1705234567890,\n \"signature\": {\n \"r\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n \"s\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n \"v\": 27\n },\n \"vaultAddress\": null\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.hyperliquid.xyz/exchange")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"action\": {\n \"type\": \"order\",\n \"orders\": [\n {\n \"a\": 0,\n \"b\": true,\n \"p\": \"50000.0\",\n \"s\": \"0.01\",\n \"r\": false,\n \"t\": {\n \"limit\": {\n \"tif\": \"Gtc\"\n }\n }\n }\n ],\n \"grouping\": \"na\"\n },\n \"nonce\": 1705234567890,\n \"signature\": {\n \"r\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n \"s\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n \"v\": 27\n },\n \"vaultAddress\": null\n}"
response = http.request(request)
puts response.read_body{
"status": "ok",
"response": {
"type": "order",
"data": {
"statuses": [
{
"resting": {
"oid": 77738308
}
}
]
}
}
}You can only use this endpoint on the official Hyperliquid public API. It is not available through Chainstack, as the open-source node implementation does not support it yet. See Hyperliquid methods for the full availability breakdown.
This endpoint requires signature authentication. See our comprehensive Authentication via Signatures guide for implementation details.
Get your own node endpoint todayStart for free and get your app to production levels immediately. No credit card required.You can sign up with your GitHub, X, Google, or Microsoft account.
Parameters
Required parameters
-
action(object, required) — The order action object containing:type(string) — Must be"order"orders(array) — Array of order objects with:a(number) — Asset index (see asset notation below)b(boolean) — Is buy order (true for buy/long, false for sell/short)p(string) — Limit price (use “0” for market orders)s(string) — Size in units of the base assetr(boolean) — Reduce only ordert(object) — Order type specification:- For limit orders:
{"limit": {"tif": "Alo" | "Ioc" | "Gtc"}} - For trigger orders:
{"trigger": {"isMarket": boolean, "triggerPx": string, "tpsl": "tp" | "sl"}}
- For limit orders:
c(string, optional) — Client order ID (128-bit hex string)
grouping(string) — Order grouping:"na"|"normalTpsl"|"positionTpsl"builder(object, optional) — Builder fee configuration:b(string) — Builder address to receive feesf(number) — Fee in tenths of a basis point
-
nonce(number, required) — Current timestamp in milliseconds (must be recent) -
signature(object, required) — EIP-712 signature of the action
Optional parameters
vaultAddress(string, optional) — Address when trading on behalf of a vault or subaccountexpiresAfter(number, optional) — Timestamp in milliseconds after which the order is rejected
Asset notation
For perpetuals, use the index from theuniverse field in the meta response. For spot assets, use 10000 + index where index is from spotMeta.universe.
Example: PURR/USDC spot has index 0 in spot metadata, so use asset 10000.
Order types
Time in Force (TIF) for limit orders
Alo— Add liquidity only (post-only), canceled if would immediately matchIoc— Immediate or cancel, unfilled portion canceledGtc— Good til canceled, rests on book until filled or canceled
Trigger orders
tp— Take profit ordersl— Stop loss orderisMarket— Whether to place market order when triggeredtriggerPx— Price at which to trigger the order
Returns
Returns an object with order placement status:status—"ok"if successfulresponse— Contains order details:type—"order"data.statuses— Array of status objects for each order:resting— Order placed on book withoid(order ID)filled— Order immediately filled withtotalSz,avgPx, andoiderror— Error message if order failed
Example request
curl -X POST https://api.hyperliquid.xyz/exchange \
-H "Content-Type: application/json" \
-d '{
"action": {
"type": "order",
"orders": [{
"a": 0,
"b": true,
"p": "50000",
"s": "0.01",
"r": false,
"t": {"limit": {"tif": "Gtc"}}
}],
"grouping": "na"
},
"nonce": 1234567890123,
"signature": {...}
}'
from hyperliquid.exchange import Exchange
from hyperliquid.utils import constants
import eth_account
# Initialize with your private key. The public mainnet API is used
# because this signing endpoint is not served through Chainstack.
account = eth_account.Account.from_key("0x...")
exchange = Exchange(account, constants.MAINNET_API_URL)
# Place a limit buy order for BTC.
order_result = exchange.order(
name="BTC",
is_buy=True,
sz=0.01,
limit_px=50000,
order_type={"limit": {"tif": "Gtc"}},
reduce_only=False,
)
print(order_result)
import { ExchangeClient, HttpTransport } from "@nktkas/hyperliquid";
import { privateKeyToAccount } from "viem/accounts";
// The default HttpTransport targets the public mainnet API because
// this signing endpoint is not served through Chainstack.
const wallet = privateKeyToAccount("0x...");
const transport = new HttpTransport();
const exchange = new ExchangeClient({ transport, wallet });
// Place a limit buy order for asset index 0 (BTC perpetual).
const result = await exchange.order({
orders: [{
a: 0,
b: true,
p: "50000",
s: "0.01",
r: false,
t: { limit: { tif: "Gtc" } },
}],
grouping: "na",
});
console.log(result);
Response examples
Successful resting order
{
"status": "ok",
"response": {
"type": "order",
"data": {
"statuses": [{
"resting": {
"oid": 77738308
}
}]
}
}
}
Filled order
{
"status": "ok",
"response": {
"type": "order",
"data": {
"statuses": [{
"filled": {
"totalSz": "0.02",
"avgPx": "1891.4",
"oid": 77747314
}
}]
}
}
}
Error response
{
"status": "ok",
"response": {
"type": "order",
"data": {
"statuses": [{
"error": "Order must have minimum value of $10."
}]
}
}
}
Use cases
- Spot and perpetual trading — Execute trades on Hyperliquid’s order books
- Algorithmic trading — Place orders programmatically with custom logic
- Risk management — Set stop-loss and take-profit orders
- Market making — Place limit orders to provide liquidity
Orders consume address-based rate limits. The
expiresAfter field consumes 5x rate limit when orders expire due to staleness.Always ensure your system clock is synchronized. Nonce must be within a reasonable time window of the current server time or the request will be rejected.
Body
application/json
Show child attributes
Show child attributes
Current timestamp in milliseconds
Example:
1734567890123
EIP-712 signature of the action. REQUIRED for authentication. Must be properly signed.
Show child attributes
Show child attributes
Address when trading on behalf of a vault or subaccount (optional)
Example:
"0x0000000000000000000000000000000000000000"
Timestamp in milliseconds after which the order is rejected (optional)
Last modified on June 24, 2026
Was this page helpful?