Market APIs
Perpetual Markets
Market structure
Name
Type
Description
id
number
Market ID: 1, 2 ...
ticker
string
CRYPTO_ETH_PERP
FOREX_GBP_PERP
min_volume
string
Min order size in USD
tick_size
string
The minimum change in the unit price of the contract
step_size
string
The minimum change in the unit size of the contract
initial_margin
string
The initial margin fraction is the margin fraction needed to open a position. Margin Fraction is calculated as your position notional amount divided by your equity. If your margin fraction exceeds the initial margin fraction, you will no longer be allowed to increase your position.
maintenance_margin
string
The maintenance margin fraction is the margin fraction needed to prevent liquidation. If your Margin Fraction exceeds the Maintenance Margin Fraction, your position will be automatically closed (liquidated) and a liquidation fee will be assessed
is_open
boolean
true: opening, false: closed
next_open
number
next market open timestamp
next_close
number
next market close timestamp
insurance_id
string
price_cap
string
The buy price of limit orders should be less or equal to (1 + cap ratio ) * Index Price
price_floor
string
The sell price of limit orders should be higher or equal to (1 - floor ratio) * Index Price
available_from
number
unavailable_after
number
null
pyth_id
string
The reference Pyth oracle pricefeed id
Get market info
Request
Endpoint: Perpetual RPC
Method:
ob_query_open_markets
Params:
[]
curl --location 'https://testnet-rpc.foundation.network/perpetual' \
--header 'Content-Type: application/json' \
--data '{
"id": "1",
"jsonrpc": "2.0",
"method": "ob_query_open_markets",
"params": []
}'
const myHeaders = new Headers();
myHeaders.append("Content-Type", "application/json");
const raw = JSON.stringify({
"id": "1",
"jsonrpc": "2.0",
"method": "ob_query_open_markets",
"params": []
});
const requestOptions = {
method: "POST",
headers: myHeaders,
body: raw,
redirect: "follow"
};
fetch("https://testnet-rpc.foundation.network/perpetual", requestOptions)
.then((response) => response.text())
.then((result) => console.log(result))
.catch((error) => console.error(error));
import requests
import json
url = "https://testnet-rpc.foundation.network/perpetual"
payload = json.dumps({
"id": "1",
"jsonrpc": "2.0",
"method": "ob_query_open_markets",
"params": []
})
headers = {
'Content-Type': 'application/json'
}
response = requests.request("POST", url, headers=headers, data=payload)
print(response.text)
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = reqwest::Client::builder()
.build()?;
let mut headers = reqwest::header::HeaderMap::new();
headers.insert("Content-Type", "application/json".parse()?);
let data = r#"{
"id": "1",
"jsonrpc": "2.0",
"method": "ob_query_open_markets",
"params": []
}"#;
let json: serde_json::Value = serde_json::from_str(&data)?;
let request = client.request(reqwest::Method::POST, "https://testnet-rpc.foundation.network/perpetual")
.headers(headers)
.json(&json);
let response = request.send().await?;
let body = response.text().await?;
println!("{}", body);
Ok(())
}
Response
{
"jsonrpc": "2.0",
"id": "1",
"result": [
{
"id": 1,
"ticker": "CRYPTO_BTC_PERP",
"min_volume": "10.00000000",
"tick_size": "0.10000000",
"step_size": "0.00100000",
"initial_margin": "0.02000000",
"maintenance_margin": "0.01000000",
"is_open": true,
"next_open": null,
"next_close": null,
"insurance_id": "0x99990d9754886ee3e99ea8526e23c15f84dd8790000000010000000000010000",
"price_cap": "1.10000000",
"price_floor": "0.90000000",
"available_from": 1000000000,
"unavailable_after": null,
"pyth_id": "0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43",
"open_interest": "2.071",
"cumulative_funding": "4.90373059",
"available_settle": "3685.45800000"
},
{
"id": 2,
"ticker": "CRYPTO_ETH_PERP",
"min_volume": "10.00000000",
"tick_size": "0.01000000",
"step_size": "0.01000000",
"initial_margin": "0.02000000",
"maintenance_margin": "0.01000000",
"is_open": true,
"next_open": null,
"next_close": null,
"insurance_id": "0x99990d9754886ee3e99ea8526e23c15f84dd8790000000010000000000010000",
"price_cap": "1.10000000",
"price_floor": "0.90000000",
"available_from": 1735977600000,
"unavailable_after": null,
"pyth_id": "0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace",
"open_interest": "1.93",
"cumulative_funding": "0.04480180",
"available_settle": "438.68360000"
}
]
}
Get market state
Request
Endpoint: Perpetual RPC
Method:
ob_query_markets_state
Params:
[]
curl --location 'https://testnet-rpc.foundation.network/perpetual' \
--header 'Content-Type: application/json' \
--data '{
"id": "1",
"jsonrpc": "2.0",
"method": "ob_query_markets_state",
"params": []
}'
const myHeaders = new Headers();
myHeaders.append("Content-Type", "application/json");
const raw = JSON.stringify({
"id": "1",
"jsonrpc": "2.0",
"method": "ob_query_markets_state",
"params": []
});
const requestOptions = {
method: "POST",
headers: myHeaders,
body: raw,
redirect: "follow"
};
fetch("https://testnet-rpc.foundation.network/perpetual", requestOptions)
.then((response) => response.text())
.then((result) => console.log(result))
.catch((error) => console.error(error));
import requests
import json
url = "https://testnet-rpc.foundation.network/perpetual"
payload = json.dumps({
"id": "1",
"jsonrpc": "2.0",
"method": "ob_query_markets_state",
"params": []
})
headers = {
'Content-Type': 'application/json'
}
response = requests.request("POST", url, headers=headers, data=payload)
print(response.text)
// Some code#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = reqwest::Client::builder()
.build()?;
let mut headers = reqwest::header::HeaderMap::new();
headers.insert("Content-Type", "application/json".parse()?);
let data = r#"{
"id": "1",
"jsonrpc": "2.0",
"method": "ob_query_markets_state",
"params": []
}"#;
let json: serde_json::Value = serde_json::from_str(&data)?;
let request = client.request(reqwest::Method::POST, "https://testnet-rpc.foundation.network/perpetual")
.headers(headers)
.json(&json);
let response = request.send().await?;
let body = response.text().await?;
println!("{}", body);
Ok(())
}
Response
{
"jsonrpc": "2.0",
"id": "1",
"result": [
{
"id": 1,
"open_interest": "5.996",
"cumulative_funding": "26.96182176",
"available_settle": "313.62590000",
"next_funding_rate": "0.00001250",
"mark_price": "98136.40370094"
},
{
"id": 2,
"open_interest": "13.50",
"cumulative_funding": "0.86193517",
"available_settle": "456.06100000",
"next_funding_rate": "0.00001250",
"mark_price": "3635.01669828"
}
]
}
Get market price
Request
Endpoint: Perpetual RPC
Method:
core_query_price
Params:
[market_id]
curl --location 'https://testnet-rpc.foundation.network/perpetual' \
--header 'Content-Type: application/json' \
--data '{
"id": "1",
"jsonrpc": "2.0",
"method": "core_query_price",
"params": [1]
}'
const myHeaders = new Headers();
myHeaders.append("Content-Type", "application/json");
const raw = JSON.stringify({
"id": "1",
"jsonrpc": "2.0",
"method": "core_query_price",
"params": [
1
]
});
const requestOptions = {
method: "POST",
headers: myHeaders,
body: raw,
redirect: "follow"
};
fetch("https://testnet-rpc.foundation.network/perpetual", requestOptions)
.then((response) => response.text())
.then((result) => console.log(result))
.catch((error) => console.error(error));
import requests
import json
url = "https://testnet-rpc.foundation.network/perpetual"
payload = json.dumps({
"id": "1",
"jsonrpc": "2.0",
"method": "core_query_price",
"params": [
1
]
})
headers = {
'Content-Type': 'application/json'
}
response = requests.request("POST", url, headers=headers, data=payload)
print(response.text)
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = reqwest::Client::builder()
.build()?;
let mut headers = reqwest::header::HeaderMap::new();
headers.insert("Content-Type", "application/json".parse()?);
let data = r#"{
"id": "1",
"jsonrpc": "2.0",
"method": "core_query_price",
"params": [
1
]
}"#;
let json: serde_json::Value = serde_json::from_str(&data)?;
let request = client.request(reqwest::Method::POST, "https://testnet-rpc.foundation.network/perpetual")
.headers(headers)
.json(&json);
let response = request.send().await?;
let body = response.text().await?;
println!("{}", body);
Ok(())
}
Response
{
"jsonrpc": "2.0",
"id": "1",
"result": {
"index_price": "98127.92327612",
"mark_price": "98128.11510258",
"last_price": "98116.2",
"index_price_time": 1736049036000
}
}
Get market statistics
Request
Endpoint: Rest API
Method:
GET /market/v1/market-info
Params:
[]
curl --location 'https://testnet-api.foundation.network/market/v1/market-info' \
--data ''
const raw = "";
const requestOptions = {
method: "GET",
body: raw,
redirect: "follow"
};
fetch("https://testnet-api.foundation.network/market/v1/market-info", requestOptions)
.then((response) => response.text())
.then((result) => console.log(result))
.catch((error) => console.error(error));
import requests
url = "https://testnet-api.foundation.network/indexer/market/v1/market-info"
payload = ""
headers = {}
response = requests.request("GET", url, headers=headers, data=payload)
print(response.text)
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = reqwest::Client::builder()
.build()?;
let data = "";
let request = client.request(reqwest::Method::GET, "https://testnet-api.foundation.network/indexer/market/v1/market-info")
.body(data);
let response = request.send().await?;
let body = response.text().await?;
println!("{}", body);
Ok(())
}
Response
[
{
"id": 1,
"lastPrice": "98347.400000000000000000",
"priceChange24h": "318.2",
"priceChangePercent24h": "0.00324597160845952022",
"highPrice24h": "99118.800000000000000000",
"lowPrice24h": "95792.300000000000000000",
"volume24h": "252.996",
"quoteVolume24h": "24800176.6354"
},
{
"id": 2,
"lastPrice": "3634.670000000000000000",
"priceChange24h": "40.41",
"priceChangePercent24h": "0.01124292622125277526",
"highPrice24h": "3674.120000000000000000",
"lowPrice24h": "3552.830000000000000000",
"volume24h": "14388.6",
"quoteVolume24h": "52228928.7604"
}
]
Query orderbook depth
Request
Endpoint: Rest API
Method:
GET indexer/market/v1/depth
Params:
[]
curl --location 'https://testnet-api.foundation.network/market/v1/depth?marketId=1' \
--data ''
const raw = "";
const requestOptions = {
method: "GET",
body: raw,
redirect: "follow"
};
fetch("https://testnet-api.foundation.network/market/v1/depth?marketId=1", requestOptions)
.then((response) => response.text())
.then((result) => console.log(result))
.catch((error) => console.error(error));
import requests
url = "https://testnet-api.foundation.network/indexer/market/v1/depth"
payload = ""
headers = {}
response = requests.request("GET", url, headers=headers, data=payload)
print(response.text)
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = reqwest::Client::builder()
.build()?;
let data = "";
let request = client.request(reqwest::Method::GET, "https://testnet-api.foundation.network/indexer/market/v1/depth")
.body(data);
let response = request.send().await?;
let body = response.text().await?;
println!("{}", body);
Ok(())
}
Response
[price, amount, cumulative amount]
{
"asks": [
[
"98363.0",
"0.003",
"0.003"
],
[
"98363.4",
"0.006",
"0.009"
]
],
"bids": [
[
"98357.2",
"0.005",
"0.005"
],
[
"98356.0",
"0.005",
"0.010"
]
]
}
Query recent trades
Request
Endpoint: Rest API
Method:
GET
/market/v1/recent-tradeParams:
[market_id]
curl --location 'https://testnet-api.foundation.network/market/v1/recent-trade?marketId=1' \
--data ''
const raw = "";
const requestOptions = {
method: "GET",
body: raw,
redirect: "follow"
};
fetch("https://testnet-api.foundation.network/market/v1/recent-trade?marketId=1", requestOptions)
.then((response) => response.text())
.then((result) => console.log(result))
.catch((error) => console.error(error));
import requests
url = "https://testnet-api.foundation.network/market/v1//recent-trade?marketId=1"
payload = ""
headers = {}
response = requests.request("GET", url, headers=headers, data=payload)
print(response.text)
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = reqwest::Client::builder()
.build()?;
let data = "";
let request = client.request(reqwest::Method::GET, "https://testnet-api.foundation.network/market/v1//recent-trade?marketId=1")
.body(data);
let response = request.send().await?;
let body = response.text().await?;
println!("{}", body);
Ok(())
}
Response
[
{
"price": "97974.300000000000000000",
"amount": "0.003000000000000000",
"time": 1736064878742,
"isBuyerMaker": false,
"quoteAmount": "293.9229",
"tx": ""
},
{
"price": "97973.200000000000000000",
"amount": "0.003000000000000000",
"time": 1736064878742,
"isBuyerMaker": false,
"quoteAmount": "293.9196",
"tx": ""
}
]
Query klines - index price
Request
Endpoint: Rest API
Method:
GET /market/v1/tradingview/index-price-kline
Params:
[market_id]
curl --location 'https://testnet-api.foundation.network/market/v1/tradingview/index-price-kline?marketId=1&interval=5m&limit=300' \
--data ''
const raw = "";
const requestOptions = {
method: "GET",
body: raw,
redirect: "follow"
};
fetch("https://testnet-api.foundation.network/market/v1/tradingview/index-price-kline?marketId=1&interval=5m&limit=300", requestOptions)
.then((response) => response.text())
.then((result) => console.log(result))
.catch((error) => console.error(error));
import requests
url = "https://testnet-api.foundation.network/market/v1/tradingview/index-price-kline?marketId=1&interval=5m&limit=300"
payload = ""
headers = {}
response = requests.request("GET", url, headers=headers, data=payload)
print(response.text)
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = reqwest::Client::builder()
.build()?;
let data = "";
let request = client.request(reqwest::Method::GET, "https://testnet-api.foundation.network/market/v1/tradingview/index-price-kline?marketId=1&interval=5m&limit=300")
.body(data);
let response = request.send().await?;
let body = response.text().await?;
println!("{}", body);
Ok(())
}
Response
[event time, open price, close price, high price, low price]
[
[
1735975200000,
"98187.153250500000000000",
"98116.758296680000000000",
"98187.153250500000000000",
"98116.758296680000000000"
],
[
1735975500000,
"98116.071479370000000000",
"98154.685000000000000000",
"98175.000000000000000000",
"98114.957718420000000000"
]
]
Query klines - last price
Request
Endpoint: Rest API
Method:
/market/v1/tradingview/last-price-kline
Params:
[market_id]
curl --location 'https://testnet-api.foundation.network/market/v1/tradingview/last-price-kline?marketId=1&interval=5m&limit=300' \
--data ''
const raw = "";
const requestOptions = {
method: "GET",
body: raw,
redirect: "follow"
};
fetch("https://testnet-api.foundation.network/market/v1/tradingview/last-price-kline?marketId=1&interval=5m&limit=300", requestOptions)
.then((response) => response.text())
.then((result) => console.log(result))
.catch((error) => console.error(error));
import requests
url = "https://testnet-api.foundation.network/market/v1/tradingview/last-price-kline?marketId=1&interval=5m&limit=300"
payload = ""
headers = {}
response = requests.request("GET", url, headers=headers, data=payload)
print(response.text)
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = reqwest::Client::builder()
.build()?;
let data = "";
let request = client.request(reqwest::Method::GET, "https://testnet-api.foundation.network/market/v1/tradingview/last-price-kline?marketId=1&interval=5m&limit=300")
.body(data);
let response = request.send().await?;
let body = response.text().await?;
println!("{}", body);
Ok(())
}
Response
[event time, open price, close price, high price, low price, volume]
[
[
1735975500000,
"98118.200000000000000000",
"98154.800000000000000000",
"98174.100000000000000000",
"98115.100000000000000000",
"0.936"
],
[
1735975800000,
"98154.200000000000000000",
"98145.200000000000000000",
"98169.100000000000000000",
"98138.900000000000000000",
"1.008"
]
]
Query klines - mark price
Request
Endpoint: Rest API
Method:
/market/v1/tradingview/last-price-kline
Params:
[market_id]
curl --location 'https://testnet-api.foundation.network/market/v1/tradingview/mark-price-kline?marketId=1&interval=5m&limit=300' \
--data ''
const raw = "";
const requestOptions = {
method: "GET",
body: raw,
redirect: "follow"
};
fetch("https://testnet-api.foundation.network/market/v1/tradingview/mark-price-kline?marketId=1&interval=5m&limit=300", requestOptions)
.then((response) => response.text())
.then((result) => console.log(result))
.catch((error) => console.error(error));
import requests
url = "https://testnet-api.foundation.network/market/v1/tradingview/mark-price-kline?marketId=1&interval=5m&limit=300"
payload = ""
headers = {}
response = requests.request("GET", url, headers=headers, data=payload)
print(response.text)
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = reqwest::Client::builder()
.build()?;
let data = "";
let request = client.request(reqwest::Method::GET, "https://testnet-api.foundation.network/market/v1/tradingview/mark-price-kline?marketId=1&interval=5m&limit=300")
.body(data);
let response = request.send().await?;
let body = response.text().await?;
println!("{}", body);
Ok(())
}
Response
[event time, open price, close price, high price, low price]
[
[
1735975500000,
"98116.786909060000000000",
"98155.298807590000000000",
"98175.644614320000000000",
"98115.652358690000000000"
],
[
1735975800000,
"98155.229146240000000000",
"98145.240516650000000000",
"98171.493843970000000000",
"98144.125872330000000000"
]
]
Query market funding history
Request
Endpoint: Rest API
Method:
GET /market/v1/funding/histories
Params:
[market_id]
curl --location 'https://testnet-api.foundation.network/market/v1/funding/histories?marketId=1' \
--data ''
const raw = "";
const requestOptions = {
method: "GET",
body: raw,
redirect: "follow"
};
fetch("https://testnet-api.foundation.network/market/v1/funding/histories?marketId=1", requestOptions)
.then((response) => response.text())
.then((result) => console.log(result))
.catch((error) => console.error(error));
import requests
url = "https://testnet-api.foundation.network/market/v1//funding/histories?marketId=1"
payload = ""
headers = {}
response = requests.request("GET", url, headers=headers, data=payload)
print(response.text)
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = reqwest::Client::builder()
.build()?;
let data = "";
let request = client.request(reqwest::Method::GET, "https://testnet-api.foundation.network/market/v1//funding/histories?marketId=1")
.body(data);
let response = request.send().await?;
let body = response.text().await?;
println!("{}", body);
Ok(())
}
Response
[
{
"value": "0.000012500000000000",
"time": 1735981200000
},
{
"value": "0.000012500000000000",
"time": 1735984800000
},
{
"value": "0.000012500000000000",
"time": 1735988400000
}
]
Subscribe trade & order of the market
Subscribe
Endpoint: Perpetual WS
Method:
ob_subscribe_order or ob_subscribe_trade
Params:
[market_id]
Code Example
import { RequestManager, Client, WebSocketTransport } from "@open-rpc/client-js";
const transport = new WebSocketTransport("wss://testnet-rpc.foundation.network");
const client = new Client(new RequestManager([transport]));
client.onNotification((ev) => {
const result = (ev.params as any).result;
if (result.status == "filled" || result.status == "partially_filled") {
console.log("filled", result);
}
});
const sub = await client.request({
method: "ob_subscribe_trade",
params: [1],
});
Subscribe trade -> notification example
{
"order_id": 24297962,
"account_id": "0x57d4ee509474b5a6459dba47f1aaa946c5c9aa1d000000000000000000000002",
"market_id": 1,
"status": "filled",
"role": "taker",
"side": "ask",
"price": "586.76",
"quote_charge": "-0.4048671000000000000000",
"base_charge": "0",
"quote_delta": "134.5508329000000000000000",
"base_delta": "-0.23",
"unsettled_pnl": "0.000000000000000000000000",
"quote_frozen_delta": "-134.9548",
"base_frozen_delta": "0",
"funding_fee": "0",
"taker_fee": null
}
Subscribe orders -> notification example
{
"order_id": 24301270,
"account_id": "0x57d4ee509474b5a6459dba47f1aaa946c5c9aa1d000000000000000000000002",
"market_id": 1,
"side": "bid",
"create_timestamp": 1712745917234,
"amount": "8.01",
"price": "587.39",
"status": "conditionally_canceled",
"matched_quote_amount": "312.2349030000000000000000",
"matched_base_amount": "0.53",
"quote_fee": "-0.9339030000000000000000",
"nonce": 1795944268134828800,
"expiration": {
"time_in_force": "immediate_or_cancel",
"reduce_only": false,
"expires_at": null,
"is_market_order": null
},
"trigger_condition": null,
"is_triggered": true,
"signature": "85636c266ed80dd4e6eba80845dc9d81b5c08f49e0ce61bcd4ce14c6082f381b43b0f7254a305e31e3c2a63dcf6b4fcd14ffe8d9dd7b993cf95beb6f7f16b9211b",
"signer": null,
"create_event_id": 591285672,
"hash": "f3a9d95bc2ab074a686971cb5c1217b41813f37c69059f96a62a8a5121d04091"
}
Last updated