curl --request GET \
--url https://staging.apimonaco.xyz/api/v1/positions/{positionId} \
--header 'X-Monaco-Signature: <api-key>'import requests
url = "https://staging.apimonaco.xyz/api/v1/positions/{positionId}"
headers = {"X-Monaco-Signature": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'X-Monaco-Signature': '<api-key>'}};
fetch('https://staging.apimonaco.xyz/api/v1/positions/{positionId}', 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://staging.apimonaco.xyz/api/v1/positions/{positionId}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"X-Monaco-Signature: <api-key>"
],
]);
$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://staging.apimonaco.xyz/api/v1/positions/{positionId}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-Monaco-Signature", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://staging.apimonaco.xyz/api/v1/positions/{positionId}")
.header("X-Monaco-Signature", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://staging.apimonaco.xyz/api/v1/positions/{positionId}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-Monaco-Signature"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"positionId": "<string>",
"marginAccountId": "<string>",
"tradingPairId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"side": "<string>",
"size": "<string>",
"entryPrice": "<string>",
"markPrice": "<string>",
"indexPrice": "<string>",
"unrealizedPnl": "<string>",
"realizedPnl": "<string>",
"isolatedMargin": "<string>",
"leverage": "<string>",
"maintenanceMarginRequired": "<string>",
"initialMarginRequired": "<string>",
"liquidationPrice": "<string>",
"status": "<string>",
"updatedAt": "<string>",
"riskBucketId": "<string>",
"marginMode": "<string>",
"netRealizedPnl": "<string>",
"realizedRoe": "<string>",
"exitPrice": "<string>",
"fundingPaid": "<string>",
"feesPaid": "<string>",
"cumFees": "<string>",
"version": 918342
}Get apiv1positions
curl --request GET \
--url https://staging.apimonaco.xyz/api/v1/positions/{positionId} \
--header 'X-Monaco-Signature: <api-key>'import requests
url = "https://staging.apimonaco.xyz/api/v1/positions/{positionId}"
headers = {"X-Monaco-Signature": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'X-Monaco-Signature': '<api-key>'}};
fetch('https://staging.apimonaco.xyz/api/v1/positions/{positionId}', 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://staging.apimonaco.xyz/api/v1/positions/{positionId}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"X-Monaco-Signature: <api-key>"
],
]);
$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://staging.apimonaco.xyz/api/v1/positions/{positionId}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-Monaco-Signature", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://staging.apimonaco.xyz/api/v1/positions/{positionId}")
.header("X-Monaco-Signature", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://staging.apimonaco.xyz/api/v1/positions/{positionId}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-Monaco-Signature"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"positionId": "<string>",
"marginAccountId": "<string>",
"tradingPairId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"side": "<string>",
"size": "<string>",
"entryPrice": "<string>",
"markPrice": "<string>",
"indexPrice": "<string>",
"unrealizedPnl": "<string>",
"realizedPnl": "<string>",
"isolatedMargin": "<string>",
"leverage": "<string>",
"maintenanceMarginRequired": "<string>",
"initialMarginRequired": "<string>",
"liquidationPrice": "<string>",
"status": "<string>",
"updatedAt": "<string>",
"riskBucketId": "<string>",
"marginMode": "<string>",
"netRealizedPnl": "<string>",
"realizedRoe": "<string>",
"exitPrice": "<string>",
"fundingPaid": "<string>",
"feesPaid": "<string>",
"cumFees": "<string>",
"version": 918342
}Authorizations
Ed25519 session-key request signing. Every authenticated request carries three headers: X-Monaco-PublicKey (64-char lowercase-hex session public key), X-Monaco-Timestamp (Unix milliseconds, within 30s of server time), and X-Monaco-Signature (hex ed25519 signature). The signature is over METHOD\npath?query\ntimestamp_ms\nSHA256_hex(body), where the body hash is the SHA-256 of the empty byte string when there is no body. Obtain the session keypair from POST /api/v1/auth/challenge followed by POST /api/v1/auth/verify.
Path Parameters
Response
OK
Margin account UUID for the isolated bucket that owns this position.
Open rows: current absolute position quantity. Terminal rows (CLOSED/LIQUIDATED/EXPIRED): total quantity closed over the position's life, summed from its reducing executions when available.
Open ISOLATED rows: principal committed to the filled position, adjusted by settled realized PnL, fees and funding, clamped at zero. Collateral allocated to unfilled orders is excluded. This is the unrealized-return denominator and the same backing used by isolated liquidation. Placing, cancelling or resizing an unfilled order does not add position backing. A price gap can pass the backing before asynchronous liquidation occurs. Live and persisted reads use the same position-principal basis. Open CROSS rows: the position's posted margin. Terminal rows: total initial margin allocated across the position's reducing executions when available, used as the basis for lifetime realized return.
Maintenance margin required by this position at mark_price using the market maintenance-margin rate. Zero when the position has no open exposure.
Initial margin required by this position at mark_price, honoring both its effective leverage and the market initial-margin floor. Zero when the position has no open exposure.
Liquidation mark-price threshold. In ISOLATED mode, this is the position/risk-bucket threshold. In CROSS mode, it is conditional: it varies only this position's mark while all other marks in the cross risk bucket remain unchanged. Other position marks, funding, realized PnL, fees/reserves, and collateral can change it. Treat an absent or blank value as unavailable, never as zero.
RFC 3339 instant at which this position was last MUTATED — a fill, collateral transfer, funding settlement or close — as the producer that owns the position recorded it. It is NOT the instant the response was built: polling an unchanged position returns the same value, and an oracle reprice does not move it. For an OPEN position every surface reports the same instant — the list, the detail read, the risk read, the WebSocket positions snapshot, and the live position_update frames.
Two cases come from the persistence clock instead and differ from the matching engine's by the persistence lag: a TERMINAL row (the live position_update frame carries the engine's close instant, this field carries the stored one), and any position read after a matching-engine restart. Accurate to that lag, not to the microsecond.
A third case is not lag-bounded: an OPEN row read while the matching engine is unreachable falls back to the row's own lifecycle columns (close, then last funding, then open), so a position filled repeatedly since it opened reports its opening instant until funding settles. The live position_update frame is unaffected.
Display metadata. version is the reconciliation key; ordering position
state by this field is never correct.
Lifetime realized PnL net of trading fees and funding. Terminal rows only; absent when the position's reducing executions are unavailable.
Lifetime realized return on the total allocated initial margin, as a percentage, computed from NET realized PnL (after trading fees and funding). The denominator is initial margin only: fees and funding are costs rather than posted collateral, and funding is signed, so folding it into the denominator could drive it to zero or negative. Terminal rows only; absent when unavailable, including when the position's reducing executions do not account for its whole lifetime.
Volume-weighted average price across the position's reducing executions. Positions closed in several fills exit at this price, not at the final fill or the mark at close. Terminal rows only; absent when the position's reducing executions do not account for its whole lifetime.
Lifetime funding paid (signed; negative means received), summed over the position's reducing executions. Terminal rows only; absent when the position's reducing executions do not account for its whole lifetime.
Trading fees paid on the position's reducing executions (signed; negative means rebated). Closing-side fees only — fees on opening fills are not included. Terminal rows only; absent when the position's reducing executions do not account for its whole lifetime.
Total lifetime trading fees for the position: opening-fill fees (from the PnL cost-basis engine) plus every reducing execution's fees — decreases, close, and any liquidation penalty. Signed; negative means net rebated, inclusive of the application-fee component. Unlike the closing-side reducing-execution fee field above, which omits opening fills, this is the whole-life figure, on open and terminal rows alike. Null when the opening-fill fees are unavailable — before the position's first PnL sample flushes, after its samples age out of PnL retention, or for positions predating the PnL service — rather than an understated partial.
Opaque, non-negative producer-owned version for this position row. Compare only within the same position; higher is newer. 0 is the unranked legacy sentinel and never participates in ordering: treat it exactly as an absent version and fall back to a full field comparison rather than ranking it as oldest. It advances on sequenced position mutations (open, add, reduce, close, funding, margin transfer, liquidation, ADL) and is shared by the persisted read, the WebSocket positions snapshot and a RANKED live position_update frame. A live frame is ranked only when it is a faithful projection of the row persisted at that sequence: in practice the fills that leave a position open. Frames that re-read live risk state after sequencing (funding, margin_added/margin_reduced) and terminal frames (which report size 0 and LIQUIDATED, while the stored row keeps its size and records CLOSED) omit the version even though the mutation did advance the persisted one, so an absent version never implies that nothing was persisted. mark_price, unrealized_pnl, liquidation_price, leverage, maintenance_margin_required and initial_margin_required are UNVERSIONED valuation fields, re-derived per payload rather than served from the versioned row: the version does not advance for them (five move with the oracle mark; leverage does not, being opening notional over posted margin, but the live surfaces derive it while the persisted row serves its stored column, so it can still disagree at an unchanged version) (a valuation-only oracle tick persists nothing; a state-transitioning one, a breach or recovery, persists the account's snapshot and restamps the positions it changed), so the merge rule is per field group — on an equal version skip the versioned fields but still take all six from the newer payload, because discarding a whole payload on an equal version freezes displayed PnL and can leave a stale margin requirement on screen. isolated_margin is the one exception among the versioned fields: the WebSocket positions snapshot overlays it from an independent live matching-engine read rather than the versioned row, so take it from the newest payload on an equal version too or a consumer can retain stale backing. The version advances exactly when the row's versioned content changed at that sequence, a change undone within one persistence batch included; a position a command left unchanged keeps its version, so a RANKED live frame for an untouched sibling of a filled position can carry a higher version than the persisted row while describing identical content — rank it as newer, and nothing changes. A response served from live matching-engine state reports 0 (unranked): the engine holds the state but not the version.
x >= 0918342
Was this page helpful?

