curl --request GET \
--url https://api.numofx.com/v1/positionsimport requests
url = "https://api.numofx.com/v1/positions"
response = requests.get(url)
print(response.text)const options = {method: 'GET'};
fetch('https://api.numofx.com/v1/positions', 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.numofx.com/v1/positions",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.numofx.com/v1/positions"
req, _ := http.NewRequest("GET", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.numofx.com/v1/positions")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.numofx.com/v1/positions")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
response = http.request(request)
puts response.read_body{
"positions": [
{
"market": "USDCcNGN-PERP",
"subaccount_id": "42",
"engine_position": "137400",
"ui_side": "long",
"ui_size": "137400",
"ui_notional_usdc": "100.0272",
"mark_price_ui": "0.0007278",
"index_price_ui": "0.000728",
"unrealized_pnl": "-0.02748",
"initial_margin_surplus": "6.63045",
"maintenance_margin_surplus": "19.96708",
"liquidation_price_ui": "0.00054615"
}
],
"accounts": [
{
"market": "USDCcNGN-PERP",
"subaccount_id": "42",
"cash": "40",
"initial_margin_surplus": "6.63045",
"maintenance_margin_surplus": "19.96708",
"collateral": [
{
"symbol": "cNGN",
"asset_address": "<string>",
"balance": "<string>",
"value_usd": "<string>",
"margin_value_usd": "<string>"
}
]
}
]
}{
"error": "<string>"
}{
"error": "<string>"
}List positions
A subaccount’s perpetual positions and margin accounts, read from chain at request time. Positions are public on chain, so no signature is required. Everything is in the cNGN-PERP orientation: prices in USDC per cNGN, sizes in cNGN, long means long cNGN and is a positive engine_position. positions holds one entry per perp market with a non-zero position; accounts one entry per enabled perp market whether or not a position is held. Both are [] rather than null when empty, and both are empty when the deployment serves no perp. Market prices and margin rates are cached for 10 seconds; the account’s balances are read fresh on every request.
curl --request GET \
--url https://api.numofx.com/v1/positionsimport requests
url = "https://api.numofx.com/v1/positions"
response = requests.get(url)
print(response.text)const options = {method: 'GET'};
fetch('https://api.numofx.com/v1/positions', 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.numofx.com/v1/positions",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.numofx.com/v1/positions"
req, _ := http.NewRequest("GET", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.numofx.com/v1/positions")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.numofx.com/v1/positions")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
response = http.request(request)
puts response.read_body{
"positions": [
{
"market": "USDCcNGN-PERP",
"subaccount_id": "42",
"engine_position": "137400",
"ui_side": "long",
"ui_size": "137400",
"ui_notional_usdc": "100.0272",
"mark_price_ui": "0.0007278",
"index_price_ui": "0.000728",
"unrealized_pnl": "-0.02748",
"initial_margin_surplus": "6.63045",
"maintenance_margin_surplus": "19.96708",
"liquidation_price_ui": "0.00054615"
}
],
"accounts": [
{
"market": "USDCcNGN-PERP",
"subaccount_id": "42",
"cash": "40",
"initial_margin_surplus": "6.63045",
"maintenance_margin_surplus": "19.96708",
"collateral": [
{
"symbol": "cNGN",
"asset_address": "<string>",
"balance": "<string>",
"value_usd": "<string>",
"margin_value_usd": "<string>"
}
]
}
]
}{
"error": "<string>"
}{
"error": "<string>"
}subaccount_id and read.
The response always has two arrays, each [] rather than null when empty:
positions— one entry per perp market where the account holds a non-zero position.accounts— one entry per enabled perp market, whether or not the account holds a position: its cash and margin surpluses are what a ticket shows as available before the first trade.
Reading a position
Everything is in the cNGN-PERP orientation: prices in USDC per cNGN, sizes in cNGN, and long means long cNGN.engine_positionis the signed cNGN balance of the perp on chain, as a decimal string with up to 18 places. Positive is a long.ui_sideislongwhenengine_positionis positive,shortwhen negative.ui_sizeis its magnitude in cNGN andui_notional_usdcthat size valued at the index, both to 6 decimal places.mark_price_uiandindex_price_uiare the market’s mark and index to 10 decimal places, the same values as theperpblock onGET /v1/markets.unrealized_pnlis the position’s unsettled and unrealized cash on chain, in USDC, signed.initial_margin_surplusandmaintenance_margin_surplusare the SRM’s own figures for the account, in USDC. Below zero means the account is under that margin; a negative maintenance surplus means it can be liquidated.liquidation_price_uiis an estimate: the price in USDC per cNGN at which the maintenance surplus reaches zero if nothing else changes, for an account holding only this position. It is omitted when no positive price gets there — a long at 1x, for example.
Reading an account
cashis the account’s balance in the perp’s CashAsset, in USDC, signed.initial_margin_surplusandmaintenance_margin_surplusare as above. For an account with no position the initial surplus is its cash.collaterallists each base asset the account has posted as margin:symbol,asset_address,balancein that asset,value_usdat the index andmargin_value_usd, the share the SRM credits after itsmargin_factor. Empty when nothing is posted, or margin is cash only.
Example
A long of 137,400 cNGN with 40 USDC of margin, at a mark of 0.0007278:{
"positions": [
{
"market": "USDCcNGN-PERP",
"subaccount_id": "42",
"engine_position": "137400",
"ui_side": "long",
"ui_size": "137400",
"ui_notional_usdc": "100.0272",
"mark_price_ui": "0.0007278",
"index_price_ui": "0.000728",
"unrealized_pnl": "-0.02748",
"initial_margin_surplus": "6.63045",
"maintenance_margin_surplus": "19.96708",
"liquidation_price_ui": "0.00054615"
}
],
"accounts": [
{
"market": "USDCcNGN-PERP",
"subaccount_id": "42",
"cash": "40",
"initial_margin_surplus": "6.63045",
"maintenance_margin_surplus": "19.96708",
"collateral": []
}
]
}
Polling
The market’s mark, index and margin rates are cached for 10 seconds server-side; the account’s balances and surpluses are read from chain on every request. The Numo app polls this endpoint every 15 seconds, which is ample: funding accrues continuously, so there is no settlement instant to catch.Errors
| Status | Error | Cause |
|---|---|---|
400 | subaccount_id is required | The query parameter is missing. |
400 | subaccount_id must be a non-negative integer | Not a base-10 unsigned integer. |
502 | could not read positions from chain | The RPC read of the position failed. Retry. |
502 | could not read the account from chain | The RPC read of the account’s margin failed. Retry. |
Query Parameters
Base-10 subaccount id, a non-negative integer.
Response
The account's perp positions and margin accounts
Was this page helpful?

